Jsonnet Cheat Sheet
Overview
Jsonnet is a data templating language that extends JSON with variables, conditionals, functions, imports, and object-oriented features. It generates JSON or YAML output, making it ideal for producing complex configuration files for Kubernetes, Terraform, CI/CD pipelines, and other infrastructure tools. Jsonnet code is purely functional with no side effects.
Jsonnet comes in two implementations: the C++ jsonnet binary and the Go-based go-jsonnet. Both produce identical output. The language has been widely adopted in the Kubernetes ecosystem through projects like ksonnet, Tanka (by Grafana), and the jsonnet-bundler package manager.
Installation
# macOS
brew install jsonnet
# Go implementation
go install github.com/google/go-jsonnet/cmd/jsonnet@latest
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@latest
# Ubuntu/Debian
sudo apt install jsonnet
# Jsonnet-bundler (package manager)
go install github.com/jsonnet-bundler/jsonnet-bundler/cmd/jb@latest
# Verify
jsonnet --version
Core Commands
| Command | Description |
|---|---|
jsonnet file.jsonnet | Evaluate and output JSON |
jsonnet -y file.jsonnet | Output as YAML stream |
jsonnet -m outdir/ file.jsonnet | Multi-file output |
jsonnet -S file.jsonnet | Output as raw string |
jsonnet -e 'expr' | Evaluate expression |
jsonnetfmt file.jsonnet | Format Jsonnet code |
jsonnetfmt -i file.jsonnet | Format in place |
Language Basics
Values and Variables
// config.jsonnet
local app_name = 'my-app';
local version = '2.0.0';
local port = 8080;
local debug = false;
{
name: app_name,
version: version,
port: port,
debug: debug,
url: 'http://localhost:%d' % port,
fullName: '%s-v%s' % [app_name, version],
}
Functions
// Helper function
local container(name, image, port) = {
name: name,
image: image,
ports: [{ containerPort: port }],
};
// With default parameters
local service(name, port=80, type='ClusterIP') = {
apiVersion: 'v1',
kind: 'Service',
metadata: { name: name },
spec: {
type: type,
ports: [{ port: port, targetPort: port }],
selector: { app: name },
},
};
{
container: container('web', 'nginx:latest', 80),
service: service('web'),
serviceNodePort: service('api', 8080, 'NodePort'),
}
Conditionals and Comprehensions
local env = 'production';
{
replicas: if env == 'production' then 3 else 1,
debug: env != 'production',
// Array comprehension
ports: [p for p in [80, 443, 8080] if p != 443],
// Object comprehension
labels: {
['app/%s' % k]: v
for k in ['name', 'version', 'team']
for v in [self.name, self.version, 'platform']
},
name: 'my-app',
version: '1.0',
}
Object Inheritance
local base = {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
labels: { managed: 'jsonnet' },
},
spec: {
replicas: 1,
template: {
spec: {
containers: [],
},
},
},
};
// Merge with +
local frontend = base {
metadata+: { name: 'frontend' },
spec+: {
replicas: 2,
template+: {
spec+: {
containers: [{
name: 'frontend',
image: 'frontend:v1',
ports: [{ containerPort: 3000 }],
}],
},
},
},
};
frontend
Configuration
Imports and Libraries
// lib/k8s.libsonnet
{
deployment(name, image, port, replicas=1): {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: name,
labels: { app: name },
},
spec: {
replicas: replicas,
selector: { matchLabels: { app: name } },
template: {
metadata: { labels: { app: name } },
spec: {
containers: [{
name: name,
image: image,
ports: [{ containerPort: port }],
}],
},
},
},
},
}
// main.jsonnet
local k8s = import 'lib/k8s.libsonnet';
local config = import 'config.json'; // Import JSON directly
{
frontend: k8s.deployment('frontend', 'frontend:v2', 3000, 2),
backend: k8s.deployment('backend', config.backendImage, 8080, 3),
}
External Variables
# Pass external variables
jsonnet --ext-str env=production --ext-code replicas=3 config.jsonnet
# Top-level arguments
jsonnet --tla-str env=production config.jsonnet
// Using external variables
local env = std.extVar('env');
local replicas = std.extVar('replicas');
// Using top-level arguments
function(env='dev', replicas=1) {
environment: env,
spec: { replicas: replicas },
}
Standard Library Highlights
{
// String operations
upper: std.asciiUpper('hello'),
split: std.split('a,b,c', ','),
format: std.format('Hello %s, you are %d', ['world', 42]),
// Array operations
sorted: std.sort([3, 1, 2]),
unique: std.uniq(std.sort([1, 2, 2, 3])),
filtered: std.filter(function(x) x > 2, [1, 2, 3, 4]),
mapped: std.map(function(x) x * 2, [1, 2, 3]),
// Object operations
keys: std.objectFields({ a: 1, b: 2 }),
merged: std.mergePatch({ a: 1 }, { b: 2 }),
// Type checks
isStr: std.isString('hello'),
isNum: std.isNumber(42),
}
Advanced Usage
Multi-File Output
// multi.jsonnet
local apps = ['frontend', 'backend', 'worker'];
{
[app + '-deployment.json']: {
kind: 'Deployment',
metadata: { name: app },
}
for app in apps
}
jsonnet -m output/ multi.jsonnet
# Creates: output/frontend-deployment.json, output/backend-deployment.json, etc.
Jsonnet Bundler (Package Manager)
# Initialize
jb init
# Install a package
jb install github.com/grafana/jsonnet-libs/ksonnet-util
# Install specific version
jb install github.com/grafana/grafonnet-lib/grafonnet@master
# Update dependencies
jb update
// Use installed package
local ksonnet = import 'ksonnet-util/kausal.libsonnet';
local k = ksonnet { _config+:: { namespace: 'myapp' } };
Grafana Tanka Integration
# Initialize Tanka project
tk init
# Apply Jsonnet to cluster
tk apply environments/default
# Diff changes
tk diff environments/default
# Show generated YAML
tk show environments/default
Troubleshooting
| Issue | Solution |
|---|---|
RUNTIME ERROR: max stack frames exceeded | Check for infinite recursion in self-references |
| Import not found | Check JSONNET_PATH or use -J flag for lib paths |
| Unexpected field merge | Use +: for deep merge, : for override |
| Output is not valid JSON | Check for trailing commas or syntax errors |
| Slow evaluation | Reduce deep recursion; cache imported libraries |
| Hidden fields in output | Use :: for hidden; ::: for visible override |
# Format code
jsonnetfmt -i *.jsonnet
# Add library search path
jsonnet -J vendor/ -J lib/ main.jsonnet
# Evaluate single expression
jsonnet -e 'std.sort([3,1,2])'
# YAML output
jsonnet -y main.jsonnet
# Verbose error output
jsonnet --max-trace 20 main.jsonnet