Pkl (pronounced "pickle") is Apple's open-source configuration language that brings type safety, validation, and IDE support to configuration files — replacing error-prone YAML, JSON, and TOML.
Why Pkl Matters
YAML configs are the #1 source of production incidents. A wrong indent, a missing quote, a string where a number should be — YAML catches none of these. Pkl catches ALL of them at evaluation time.
What you get for free:
- Static types and validation for all configuration
- IDE support with auto-complete (VS Code, IntelliJ)
- Generates YAML, JSON, plist, or Java/Kotlin/Swift properties
- Templates and inheritance — DRY configuration
- Constraints and validation built into the schema
- Package management for sharing config schemas
Quick Start
# Install
curl -fsSL https://pkl-lang.org/install.sh | sh
# Evaluate a Pkl file to YAML
pkl eval config.pkl -f yaml
# Evaluate to JSON
pkl eval config.pkl -f json
# Validate against schema
pkl eval --project-dir . config.pkl
Basic Configuration
// config.pkl
name = "my-api"
version = "2.1.0"
port = 8080
database {
host = "db.example.com"
port = 5432
name = "mydb"
maxConnections = 20
ssl = true
}
redis {
host = "redis.example.com"
port = 6379
ttlSeconds = 3600
}
Generates clean YAML:
name: my-api
version: 2.1.0
port: 8080
database:
host: db.example.com
port: 5432
name: mydb
maxConnections: 20
ssl: true
redis:
host: redis.example.com
port: 6379
ttlSeconds: 3600
Type Safety and Validation
// schema.pkl
class DatabaseConfig {
host: String
port: Int(isBetween(1, 65535)) // Port must be valid
name: String(!isEmpty) // Cannot be empty
maxConnections: Int(isPositive) // Must be > 0
ssl: Boolean
}
class AppConfig {
name: String(matches(Regex("[a-z][a-z0-9-]+")))
version: String(matches(Regex("\\d+\\.\\d+\\.\\d+")))
port: Int(isBetween(1024, 65535))
database: DatabaseConfig
}
// This FAILS at evaluation time:
// port = 99999 // Error: 99999 is not between 1 and 65535
// name = "" // Error: cannot be empty
Environment-Specific Configs
// base.pkl
abstract class Environment {
name: String
replicas: Int
database: DatabaseConfig
logLevel: "debug"|"info"|"warn"|"error"
}
// production.pkl
amends "base.pkl"
name = "production"
replicas = 5
logLevel = "warn"
database {
host = "prod-db.internal"
port = 5432
maxConnections = 100
ssl = true
}
// staging.pkl
amends "base.pkl"
name = "staging"
replicas = 2
logLevel = "debug"
database {
host = "staging-db.internal"
port = 5432
maxConnections = 20
ssl = true
}
Kubernetes Configs
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/api/apps/v1/Deployment.pkl"
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/api/core/v1/Service.pkl"
local name = "web-api"
local image = "myregistry/web-api:v2.1.0"
deployment = new Deployment {
metadata { name = name; namespace = "default" }
spec {
replicas = 3
selector { matchLabels { ["app"] = name } }
template {
metadata { labels { ["app"] = name } }
spec {
containers {
new {
name = name
image = image
ports { new { containerPort = 8080 } }
}
}
}
}
}
}
Useful Links
Building automated data pipelines? Check out my developer tools on Apify for ready-made web scrapers, or email spinov001@gmail.com for custom solutions.
Top comments (0)