Better configuration for less
Nickel
Nickel is the universal configuration language. Nickel is configuration templating, but done right. Modular, correct and concise.
Its purpose is to automate the generation of static configuration files - think JSON, YAML, XML, or your favorite data representation language - that are then fed to another system. It is designed to have a simple, well-understood core: it is in essence JSON with functions.
Nickel's salient traits are:
- Lightweight: Nickel is easy to embed. An interpreter should be simple to
- Composable code: the basic building blocks for computations are functions.
- Composable data: the basic building blocks for data are records (JSON's
- Typed, but only when it helps: on the one hand, static types improve code
On the other hand, most configuration data are static. In this case, dynamic type errors are often simple and sufficient. Additionally, some JSON schemas are hard to translate to more rigid types.
Nickel features a (sound) gradual type system: it has types, but you get to choose when you want to use them or not. You can statically check complex functions, but use more flexible runtime validation for configuration data.
- Design by contract: contracts are a principled approach to validation.
The motto guiding Nickel's design is:
Great defaults, design for extensibility
There should be one clear and simple path for common tasks. But the day you need to go beyond, there should be no arbitrary restrictions that limit what you can do.
Who we are
Nickel is designed, developed, and maintained by Tweag, a part of Modus Create. We develop it in the open, and gratefully accept community feedback and contributions.
Use cases
Nickel is a good fit in any situation where you need to generate a complex configuration, be it for a single app, a machine, whole infrastructure, or a build system.
The motivating use cases are in particular:
- The Nix package manager: Nix is a declarative package
- Infrastructure as code: infrastructure is becoming increasingly complex,
- Build systems: build systems (like Bazel) need
Most aforementioned projects have their own bespoke configuration language. See Comparison. In general, application-specific languages might suffer from feature creep, lack of abstractions or just feel ad hoc. Nickel buys you more for less.
The Nickel ecosystem
Related projects that are part of the Nickel ecosystem:
- nickel-kubernetes: a collection
- Terraform-Nickel: write Terraform
- Organist: batteries included
- rules_nickel: generate
- The nickel-lang organization hosts various
Getting started
Please follow the getting started guide for Nickel users on the nickel-lang website. The instructions below are either reproduced for this document to be self-contained or because they are aimed toward hacking on the Nickel interpreter itself (e.g. building the nickel-lang-core crate documentation).
Run
- Get a Nickel binary:
nix run nixpkgs#nickel. You can use our binary
cache to prevent rebuilding a lot of
packages. Pass arguments to Nickel with an extra -- as in nix run
nixpkgs#nickel -- repl. Use github:tweag/nickel to run the unstable
version (master in practice).
- Again with flake-enabled Nix, you can install Nickel in your profile with
nix profile install nixpkgs#nickel. The nickel command is then in your
$PATH and is available anywhere.
- If you're running macOS you can use Homebrew to install the Nickel binary
with brew install nickel.
- Without Nix, you can use cargo run --bin nickel after building,
passing arguments with an extra -- as in
cargo run --bin nickel -- eval program.ncl.
- Run your first program:
$ nickel eval <<< '["hello", "world"] |> std.string.join ", "'
"hello, world"
Or load it from a file:
$ echo 'let s = "world" in "hello, %{s}"' > program.ncl
$ nickel eval program.ncl
"hello, world"
- Start a REPL:
$ nickel repl
nickel> {"hello" = true, "world" = true, "universe" = false}
|> std.record.to_array
|> std.array.filter (fun {field, value} => value)
|> std.array.map (fun {field, value} => field)
|> std.string.join ", "
"hello, world"
Use :help for a list of available commands.
- Export your configuration to JSON, YAML or TOML:
$ nickel export --format json <<< '{content = "hello, world"}' { "content": "hello, world" }
Use nickel help for a list of subcommands, and nickel help <subcommand> for help about a specific subcommand.
To get in touch, you can join our [][discord] server.
Editor Setup
Nickel has syntax highlighting plugins for Vim/Neovim, Emacs and VSCode. It also has a tree-sitter grammar which provides highlighting in an editor-independent way. The Nickel Language Server (NLS) provides in-editor diagnostics, type hints, and auto-completion. Please follow the LSP guide to set up syntax highlighting and NLS.
Formatting
To format one or several Nickel source files, use nickel format:
nickel format network.ncl container.ncl api.ncl
Nickel uses Topiary to format Nickel code under the hood. The Nickel Language Server also provides formatting capabilities out of the box.
Build
[rust-guide]: https://doc.rust-lang.org/cargo/getting-started/installation.html
- Download build dependencies:
nix-shell # if you don't use Nix flakes
nix develop # if you use Nix flakes
You will be dropped in a shell, ready to build. You can use our binary cache to prevent rebuilding a lot of packages. - Without Nix: otherwise, follow [this guide][rust-guide] to install Rust and Cargo first.
- Build Nickel:
cargo build -p nickel-lang-cli --release
And voilร ! Generated files are placed in target/release.
You can directly build and run the Nickel binary and pass argument after -- by using cargo run:
cargo run --bin nickel --release -- eval foo.ncl
Test
Run tests with
cargo test
Documentation
The user manual is available on the nickel-lang.org website, and in this repository as a collection of Markdown files in doc/manual.
To get the documentation of the nickel-lang codebase itself:
- Build the doc:
cargo doc --no-deps
- Open the file
target/doc/nickel/index.htmlin your browser.
Examples
You can find examples in the ./examples directory.
Current state and roadmap
Since version 1.0 released in May 2023, the core design of the language is stable and Nickel is useful for real-world applications. The next steps we plan to work on are:
The next steps we plan to work on are:
- Incremental evaluation: design an incremental evaluation model and a caching
- Implement a bytecode compiler and virtual machine
- Custom merge functions (second part of the
Comparison
- CUE is a configuration language with a focus on data
- Nix: The Nix language, or Nix expressions, is one of
- Dhall is a statically typed configuration language.
- Jsonnet is another language which could be dubbed as
- KCL is a gradually typed configuration language whose
- Pulumi is not a language in itself, but a cloud
- Starlark is
See RATIONALE.md for the design rationale and a more detailed comparison with these languages.
Comparison with other configuration languages
| Language | Typing | Recursion | Evaluation | Side-effects | |----------|-------------------------------|------------|------------|--------------------------------------------------| | Nickel | Gradual (dynamic + static) | Yes | Lazy | Yes (constrained, planned) | | Starlark | Dynamic | No | Strict | No | | Nix | Dynamic | Yes | Lazy | Predefined and specialized to package management | | Dhall | Static (requires annotations) | Restricted | Lazy | No | | CUE | Static (everything is a type) | No | Lazy | No, but allowed in the separated scripting layer | | Jsonnet | Dynamic | Yes | Lazy | No | | KCL | Gradual (dynamic + static) | Yes | Strict | No | | JSON | None | No | Strict | No | | YAML | None | No | N/A | No | | TOML | None | No | N/A | No |
[discord]: https://discord.gg/vYDnJYBmax