Nickel: a configuration language with contracts, for people who outgrew YAML
Better configuration for less
At a glance
- What is it?
- Nickel is a typed configuration language from Tweag that generates JSON, YAML or TOML from composable records. Its real mechanism is the merge operator plus contracts, and that is also where the sharp edges are.
- Who is it for?
- Adopt Nickel when you generate configuration that has to be merged from several sources and validated before it reaches a downstream system, and when you are willing to write contracts for that validation. Skip it if you only need a fixed file with no variants or if your team cannot take a new language in the toolchain.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Nickel solves: generating config that has to be merged and checked
Most projects do not suffer from writing configuration once. They suffer from the second, third and tenth variant of the same configuration. A base file, an environment overlay, a per-customer patch, a build-system fragment. YAML has no merge semantics that survive contact with a real team, and JSON has none at all. The README frames the target plainly: Nickel automates "the generation of static configuration files - think JSON, YAML, XML, or your favorite data representation language - that are then fed to another system."
The audience follows from that. The motivating use cases named in the README are the Nix package manager, infrastructure as code in the style of Terraform, NixOps or Kubernetes, and build systems such as Bazel. What those have in common is that each already ships a bespoke configuration language, and the README's argument is that such languages "might suffer from feature creep, lack of abstractions or just feel ad hoc." Nickel is aimed at the person who has hit the ceiling of a bespoke format and wants functions, types and validation without adopting a general-purpose programming language for the job.
It is not aimed at someone who needs a single static file. If your configuration never varies by environment and never gets overridden, a plain YAML file is cheaper to read and cheaper to review.
Records, merge and contracts: how Nickel actually works
The core is small by design. The README describes Nickel as "in essence JSON with functions", and the two data-level building blocks are records (JSON objects) and the merge operator. Merging is not a textual concatenation. Records "can be composed through the merge operator, combining metadata as well (documentation, default values, type contracts, etc)." That sentence carries most of the design: when two records are merged, the attached metadata travels with the fields, so a default value defined in a base record and an override defined in an overlay resolve according to merge semantics rather than by whichever file was concatenated last.
The second mechanism is contracts. The README calls contracts "a principled approach to validation" and says that in a Nickel configuration they "act like schemas." A contract is attached to a value as an annotation, and it is checked when the configuration is evaluated. This is the part that distinguishes Nickel from a templating engine: the check happens against the data, not against the text that produced it.
Typing is deliberately partial. Nickel has a "(sound) gradual type system": you can statically check functions and leave configuration data to runtime validation. The README justifies this on the grounds that most configuration data is static, that dynamic type errors are often sufficient there, and that some JSON schemas are hard to express in a rigid type system. That is a reasonable position, but it means the type checker will not catch everything, and the burden of deciding where the boundary sits falls on whoever writes the config.
The repository layout reflects this architecture. The Cargo workspace splits the interpreter into crates: core, parser, cli, fmt, lsp/nls, package, git, vector, flock, wasm-repl and py-nickel. The py-nickel and wasm-repl members are the concrete form of the README's claim that Nickel is "easy to embed" and that "the reference interpreter can be called from many programming languages."
Installing Nickel and evaluating a first configuration
The README points users at the getting started guide on nickel-lang.org and reproduces a few entry points. With flake-enabled Nix you can run the interpreter without installing it, or install it into your profile so the nickel command is on your PATH:
nix profile install nixpkgs#nickel
nickel --versionOn macOS the README gives Homebrew as an alternative. Both routes produce the same binary.
brew install nickelIf you prefer to build from source, the README says to use cargo run --bin nickel after building, passing arguments after an extra --. The workspace pins edition 2024 and rust-version 1.89, so the toolchain requirement is not trivial.
cargo run --bin nickel -- eval program.nclTo check that the interpreter works, the README gives a one-liner that pipes a list through std.string.join. The expected output is the quoted string, including the quotes, because Nickel prints the evaluated value:
nickel eval <<< '["hello", "world"] |> std.string.join ", "'The same example from a file shows string interpolation. Writing let s = "world" in "hello, %{s}" into program.ncl and evaluating it produces "hello, world". For interactive work, nickel repl starts a REPL, and :help lists the available commands. The README's REPL example chains std.record.to_array, std.array.filter, std.array.map and std.string.join over a record, which is the shortest demonstration of the standard library's shape.
Where Nickel gets in the way
The gradual type system is the first place to be careful. Because configuration data is validated at runtime by default, a contract that is never exercised on a particular code path will not report anything. Nickel will not tell you that a field is missing if nothing evaluates that field. The README presents this as a deliberate trade-off, and it is, but it shifts work to test coverage of the configuration itself.
Contracts are also code you have to write and maintain. The README lists json-schema-to-nickel for generating contracts from JSON schema specifications, which helps when a schema already exists. When it does not, you are writing validation by hand, and a wrong contract is worse than no contract because it produces confidence without the corresponding check.
The README is silent on several operational questions that come up during adoption. It does not document rollback behaviour, it does not describe what happens when a merge produces conflicting definitions beyond referring to metadata combination, and it does not give a migration path from an existing YAML or Nix codebase. Those gaps matter more than the language design if you are converting a large configuration tree.
Finally, the toolchain is not light. The workspace requires Rust 1.89 and edition 2024, and the Cargo.toml comments note that updating Cargo.lock breaks the Nix build until flake.nix hashes are updated. If you consume Nickel as a Rust crate, you inherit that coupling only indirectly, but if you build it yourself, you own it.
Nickel against Dhall and Jsonnet
The obvious comparison is with Dhall and Jsonnet, the two other languages built for the same job. The difference in approach is in the type system and the validation model.
Jsonnet is dynamically typed and its composition story is object inheritance with the + operator and the self/super references. It is small, it embeds easily in other programs, and it has no static checking at all. Nickel instead offers a gradual type system, so you can write statically checked functions and leave data to contracts. If your team already knows Jsonnet, the migration buys you static checking on the parts of the configuration that are genuinely code, at the cost of a larger language surface.
Dhall is the opposite bet: total, statically typed, no general recursion, and a normalization guarantee that every expression reduces to a normal form. Nickel does not make that guarantee, and the README's justification is that rigid types make some JSON schemas hard to express. Contracts are the escape hatch Dhall does not offer. If your priority is that every configuration terminates and type-checks before it runs, Dhall's constraints are a feature. If your priority is expressing a schema that resists a rigid encoding, Nickel's contracts are the more practical tool.
Neither comparison is settled by the README, which links to a Comparison section rather than reproducing it. Read that section on the website before choosing.
Licence and the cost of keeping up
Nickel is MIT licensed, both in the repository metadata and in the workspace package declaration. MIT is permissive: it allows use, modification and redistribution with the copyright notice and licence text retained. Embedding the interpreter in a proprietary product is not blocked by the licence itself. This is not legal advice, and if you are redistributing a modified interpreter you should have counsel read the actual LICENSE file rather than a summary.
The upgrade cadence is visible from the releases. The repository shows 1.16.0 on 2026-02-27, 1.17.0 on 2026-06-09 and 1.18.0 on 2026-09-19, with the last push to the default branch on 2026-09-22. That is roughly a minor release every three to four months. The workspace version and the internal crate versions do not move together: the workspace is at 1.18.0 while nickel-lang-core is at 0.19.0, nickel-lang-package at 0.8.0 and nickel-lang-parser at 0.4.0. If you depend on a crate rather than the binary, expect the crate versioning to be independent of the CLI version you read about in release notes.
The RELEASES.md and RELEASING.md files exist at the repository root, so release notes are maintained in-tree rather than only on the website. Check RELEASES.md for breaking changes before moving a pinned version, particularly across a minor bump.
Editorial conclusion
Adopt Nickel when you generate configuration that has to be merged from several sources and validated before it reaches a downstream system, and when you are willing to write contracts for that validation. Skip it if you only need a fixed file with no variants or if your team cannot take a new language in the toolchain. Before committing, verify three things: that the contracts you need exist in nickel-kubernetes or json-schema-to-nickel, that your CI can install the binary through Nix, Homebrew or Cargo, and that the merge priorities in examples/merge-priorities match how you expect overriding to behave.
Frequently asked questions
What is Nickel used for?
Nickel generates static configuration files such as JSON, YAML or XML that are then consumed by another system. The README names the Nix package manager, infrastructure as code, and build systems such as Bazel as the motivating use cases.
How do I install Nickel?
The README gives three routes: nix profile install nixpkgs#nickel with flake-enabled Nix, brew install nickel on macOS, or building from source and running cargo run --bin nickel. The getting started guide on nickel-lang.org is the recommended starting point.
What is a contract in Nickel?
A contract is Nickel's validation mechanism, attached to a value as an annotation and checked when the configuration is evaluated. The README describes contracts as acting like schemas, and they can be written by hand, mixed with existing contracts, or generated from JSON schema with json-schema-to-nickel.
Is Nickel statically typed?
Partly. The README describes a sound gradual type system: you can statically check complex functions while using runtime validation for configuration data. The stated reason is that most configuration data is static and that some JSON schemas are hard to translate to rigid types.
What is the Nickel licence?
MIT, according to both the repository metadata and the workspace package declaration in Cargo.toml.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nickel-lang-nickel)