Jsonnet Configuration
Crow supports Jsonnet as an alternative to YAML for defining pipeline configurations. Jsonnet is a data templating language that produces JSON (or YAML) output, enabling dynamic and programmable pipeline definitions that go beyond what static YAML can express.
Why Jsonnet?
Section titled “Why Jsonnet?”While YAML with anchors and aliases covers basic reuse, Jsonnet offers:
- Dynamic values: Compute matrix entries, image tags, or step lists programmatically instead of listing them statically.
- True variables: Define variables once and use them anywhere, including inside strings --- unlike YAML anchors which can only substitute entire values.
- Functions and abstractions: Write reusable functions to generate step definitions, reducing duplication across workflows.
- Conditionals: Branch pipeline logic based on CI metadata (repo, event, branch) at config parse time.
- Imports: Split configuration across multiple files with
importand share libraries across repositories.
Getting started
Section titled “Getting started”Create a .crow.jsonnet file (instead of .crow.yaml) in your repository root, or place .jsonnet files inside a .crow/ directory.
A minimal example:
This Jsonnet evaluates to a JSON object which Crow then parses as a workflow definition, just like YAML.
Full example
Section titled “Full example”The following example demonstrates a realistic CI pipeline for a Go project with linting, testing, and multi-database integration tests. It uses Jsonnet functions to eliminate the repetition that would otherwise require YAML anchors and copy-paste.
Compare this to the equivalent YAML.
The Jsonnet version avoids repeating the image name, depends_on, and apk add install line in every step, and the three database test steps are generated from a single function call each rather than three near-identical blocks.
Config file detection
Section titled “Config file detection”Crow searches for configuration files in the following order:
.crow/(directory: may contain.yaml,.yml,.jsonnet, and.libsonnetfiles).crow.yaml.crow.yml.crow.jsonnet.woodpecker/(directory).woodpecker.yaml.woodpecker.yml
The first match wins.
When using the .crow/ directory, Jsonnet and YAML files can coexist.
Each file becomes a separate workflow.
Dynamic matrices
Section titled “Dynamic matrices”One of the primary use cases for Jsonnet is generating matrix definitions programmatically:
A more advanced example that computes a matrix from structured data:
Using CI metadata
Section titled “Using CI metadata”Crow passes all CI environment variables as Jsonnet external variables, accessible via std.extVar().
These are the same variables available as ${CI_REPO} etc. in YAML variable substitution.
See Environment Variables for the full list of available variables.
Imports and libraries
Section titled “Imports and libraries”Jsonnet files can import other files using the import keyword.
Library files use the .libsonnet extension by convention and are not evaluated as standalone workflows.
.crow/lib.libsonnet:
.crow/build.jsonnet:
.crow/test.jsonnet:
Multiple workflows from a single file
Section titled “Multiple workflows from a single file”If a Jsonnet file evaluates to a JSON array, each element becomes a separate workflow:
This is equivalent to having two separate YAML files, one for each workflow.
Processing order
Section titled “Processing order”Jsonnet evaluation happens before all other pipeline processing steps:
- Jsonnet evaluation ---
.jsonnetfiles are evaluated to produce YAML/JSON - Matrix expansion ---
matrix:definitions generate workflow variants - Variable substitution ---
${CI_REPO}and similar placeholders are replaced - YAML parsing --- the final YAML is parsed into the internal workflow model
- Linting --- the parsed workflow is validated
- Compilation --- the workflow is compiled into executable steps
This means Jsonnet output can use all standard YAML features like matrix:, when:, depends_on:, ${VAR} substitution, and everything else documented in the workflow syntax reference.
CLI linting
Section titled “CLI linting”Jsonnet files can be linted using the CLI, just like YAML files:
When linting a directory, .jsonnet files are picked up alongside .yaml and .yml files.
Sibling .libsonnet files in the same directory are available for imports.