Getting started

Nickel is still young and the installation process is not yet optimal. Sorry about that! We are focused on improving the experience, so stay tuned.

We give three alternative ways of obtaining a running Nickel executable:
  1. Using Nix
  2. Using Cargo
  3. Using Docker
If you have neither of these tools, Nix is the preferred way. If you don't have Nix but you are a user of Cargo or Docker, you may prefer the corresponding installation method.

Get a Nickel binary using Nix

Run

With a recent version of Nix (> 2.4.0), you can build an run Nickel in one shot. If you haven't installed Nix yet, please follow this installation guide. Once Nix is installed, use nix run to start Nickel and append -- args to pass arguments to the Nickel executable (here we launch an REPL session)

nix run --experimental-features "flakes nix-command" github:tweag/nickel -- repl
nickel>

Install

If you are planning to try Nickel a bit more extensively, you can install the Nickel binary using nix profile:

nix profile install github:tweag/nickel
nickel repl
nickel>

Get a Nickel binary using Cargo

If you are a Rust developer, the Cargo build tool is an alternative to install a Nickel binary:

cargo install nickel-lang
nickel repl
nickel>

Get a Docker image

A last alternative is to use Docker: you can download the nickel-0.1.0-docker-image.tar.gz. Please refer to the official Docker documentation to know how to load and run a Docker image.

Write your first configuration

Nickel has advanced features to help you handle and organize complex configurations (gradual typing, contracts, a merge system, and so on). But you'll only have to deal with any of this once you need to. Writing a basic configuration is as simple as writing JSON or YAML. Let us write a manifest of a fictional app:

{
  name = "example",
  description = m%"
    This is an awesome software I'm developing.
    Please use it!
  "%m,
  version = "0.1.1",
  main = "index.js",
  keywords = ["example", "config"],
  scripts = {
    test = m%"test.sh --option --install example --version "0.1.1""%m,
    do_stuff = "do_stuff.sh subcommand",
  },
  contributors = [{
      name = "John Doe",
      email = "johndoe@example.com"
    }, {
      name = "Ivy Lane",
      url = "https://example.com/ivylane"
    }],
  dependencies = {
    dep1 = "^1.0.0",
    dep3 = "6.7"
  }
}

This program is composed of a record. A record is the same thing as an object in JSON, that is a list of key-value pairs delimited by { and }. In general, the values of Nickel map directly to corresponding values in JSON (excluding functions). Thus, the basic datatypes of Nickel are the same as in JSON:
  • Records (objects), delimited by { and }.
  • Strings, delimited by ". The sequence m%" and "%m delimits multiline strings.
  • Numbers
  • Lists, delimited by [ and ] and separated by ,.

Multiline strings are an alternative way of defining strings. Line 11 is an example of such a string. Without diving into the details, multiline strings are useful for:
  • Write strings spanning several lines, as their name suggests. Multiline strings can be indented at the same level as the surrounding code while still producing the expected result (the common indentation prefix is stripped).
  • Write strings with special characters without having to escape them.
In our example, using a multiline string saves us from escaping the recurring double quotes ".

Export

The ultimate goal of a Nickel program is to produce a static configuration. To do so, save the content of our example above in example.ncl and run nickel export:

./result/bin/nickel -f example.ncl export --format yaml
---
contributors:
  - email: johndoe@example.com
    name: John Doe
  - name: Ivy Lane
    url: https://example.com/ivylane
dependencies:
  dep1: ^1.0.0
  dep3: "6.7"
description: "This is an awesome software I'm developing.\nPlease use it!"
keywords:
  - example
  - config
main: index.js
name: example
scripts:
  do_stuff: do_stuff.sh subcommand
  test: "test.sh --option --install example --version \"0.1.1\""
version: 0.1.1

Nickel currently supports exporting to and importing from YAML, TOML and JSON.

Reuse

Nickel is a programming language. This allows you not only to describe, but to generate data. There's repetition in our previous example:

name = "example",
version = "0.1.1",
scripts = {
  test = m%"test.sh --option --install example --version "0.1.1""%m,

The version 0.1.1 appears both in version and scripts.test. The name example appears both in name and scripts.test as well. Pure aesthetics aside, a more serious issue is inconsistency. If you bump the version number in version, you may forget to do so in the scripts.test as well, ending up wih incoherent version numbers in the same configuration. To remedy the problem, let's have a single source of truth by reusing the value of name and version in scripts.test, using the string interpolation syntax %{expr}:

name = "example",
version = "0.1.1",
scripts = {
  test = m%"test.sh --option --install %{name} --version "%{version}""%m

Now, if we change version to 0.1.2 and export the result, the test script invocation is updated as well:

# [...]
scripts:
  do_stuff: do_stuff.sh subcommand
  test: "test.sh --option --install example --version \"0.1.2\""
  version: 0.1.2

Going further

This short introduction should get you started. Nickel is a full-fledged programming language, featuring higher-order functions, gradual typing, contracts, and more! To explore further, read the user manual. You will also find examples in the repository. For an overview of Nickel and the motivations behind it, see the README and the design rationale document.