DEV Community

Alex Spinov
Alex Spinov

Posted on

Pkl Has a Free API: Apple's Configuration Language That Replaces YAML and JSON

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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 } }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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)