DEV Community

Alex Spinov
Alex Spinov

Posted on

Pkl Has a Free API — Apple's Configuration Language That Validates Before Deploy

TL;DR

Pkl (pronounced "Pickle") is Apple's open-source configuration language that catches errors at evaluation time — before your config reaches production. It generates JSON, YAML, and property lists from type-safe, programmable templates.

What Is Pkl?

Pkl solves the "bad config in production" problem:

  • Type-safe — catch config errors before deployment
  • Programmable — classes, functions, conditionals, imports
  • Multi-output — generates JSON, YAML, plist, Java, Kotlin, Swift, Go
  • Modular — packages, imports, and inheritance
  • IDE support — IntelliJ, VS Code extensions
  • Free — Apache 2.0, by Apple

Quick Start

# Install
curl -L https://github.com/apple/pkl/releases/latest/download/pkl-macos-amd64 -o pkl
chmod +x pkl

# Or via Homebrew
brew install pkl
Enter fullscreen mode Exit fullscreen mode

Basic Pkl Configuration

// config.pkl
name = "my-api"
version = "2.1.0"
port = 8080

database {
  host = "db.example.com"
  port = 5432
  name = "myapp"
  maxConnections = 20
  ssl = true
}

redis {
  host = "redis.example.com"
  port = 6379
  ttl = 3600
}
Enter fullscreen mode Exit fullscreen mode
# Generate JSON
pkl eval config.pkl -f json

# Generate YAML
pkl eval config.pkl -f yaml
Enter fullscreen mode Exit fullscreen mode

Type Safety

// schema.pkl — define your config schema
class DatabaseConfig {
  host: String
  port: Int(isBetween(1, 65535))
  name: String
  maxConnections: Int(isPositive)
  ssl: Boolean
}

class AppConfig {
  name: String(!isEmpty)
  version: String(matches(Regex("\\d+\\.\\d+\\.\\d+")))
  port: Int(isBetween(1024, 65535))
  database: DatabaseConfig
}
Enter fullscreen mode Exit fullscreen mode
// production.pkl — this FAILS at eval time if invalid
amends "schema.pkl"

name = "my-api"
version = "not-a-version"  // ERROR: doesn't match semver regex
port = 80                   // ERROR: not between 1024-65535
database {
  host = "db.prod.com"
  port = 99999              // ERROR: not between 1-65535
  maxConnections = -5       // ERROR: not positive
}
Enter fullscreen mode Exit fullscreen mode

Environments with Inheritance

// base.pkl
name = "my-api"
replicas = 1
logLevel = "info"

database {
  maxConnections = 10
  ssl = true
}
Enter fullscreen mode Exit fullscreen mode
// production.pkl
amends "base.pkl"

replicas = 5
logLevel = "warn"

database {
  host = "db.prod.internal"
  maxConnections = 50
}
Enter fullscreen mode Exit fullscreen mode
// staging.pkl
amends "base.pkl"

replicas = 2

database {
  host = "db.staging.internal"
  maxConnections = 20
}
Enter fullscreen mode Exit fullscreen mode

Generating Kubernetes YAML

// k8s-deployment.pkl
import "package://pkg.pkl-lang.org/pkl-k8s/k8s@1.0.1#/api/apps/v1/Deployment.pkl"

local config = import("config.pkl")

output {
  renderer = new YamlRenderer {}
}

new Deployment {
  metadata {
    name = config.name
    namespace = "default"
  }
  spec {
    replicas = config.replicas
    template {
      spec {
        containers {
          new {
            name = config.name
            image = "myregistry/\(config.name):\(config.version)"
            ports {
              new { containerPort = config.port }
            }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Pkl vs Alternatives

Feature Pkl YAML JSON Jsonnet CUE
Type safety Strong None None Weak Strong
Validation Built-in External External Limited Built-in
Functions Yes No No Yes Yes
Classes Yes No No No Definitions
IDE support Good Basic Basic Fair Fair
Learning curve Medium Low Low Medium High
Code generation 8 languages N/A N/A JSON only JSON/YAML

Resources


Managing configuration for data pipelines? My Apify scraping tools extract web data with configurable parameters — use Pkl for type-safe scraper configs. Questions? Email spinov001@gmail.com

Top comments (0)