File Format

Sentinel uses KDL as its primary configuration format. KDL is a human-friendly document language that’s easy to read, write, and diff.

Why KDL?

FeatureBenefit
Human-readableClean syntax without excessive punctuation
Git-friendlyDiffs are clear and meaningful
Typed valuesNumbers, strings, booleans, null
CommentsBoth line (//) and block (/* */)
HierarchicalNatural nesting for configuration blocks

Basic Syntax

Nodes

KDL documents are made of nodes. Each node has a name and optional values/properties:

// Simple node
server

// Node with a value
worker-threads 4

// Node with a property
listener "http" address="0.0.0.0:8080"

// Node with children (block)
server {
    worker-threads 4
    max-connections 10000
}

Values and Properties

Values are positional arguments:

route "api"           // "api" is a value
targets "10.0.0.1" "10.0.0.2"  // Multiple values

Properties are named with =:

target address="10.0.0.1" weight=5
health-check type="http" interval-secs=10

Data Types

// Strings (quoted)
name "my-service"

// Numbers (integer or float)
port 8080
weight 1.5

// Booleans
enabled true
disabled false

// Null
optional-field null

Comments

// Line comment

/* Block comment
   spanning multiple
   lines */

server {
    worker-threads 4  // Inline comment
}

File Structure

A typical Sentinel configuration has these top-level blocks:

// Server settings
server {
    // ...
}

// Network listeners
listeners {
    // ...
}

// Request routing
routes {
    // ...
}

// Backend servers
upstreams {
    // ...
}

// External agents (optional)
agents {
    // ...
}

// Request/response limits
limits {
    // ...
}

// Logging and metrics (optional)
observability {
    // ...
}

Schema Versioning

Sentinel configurations include a schema version for compatibility checking. This helps catch configuration issues when upgrading Sentinel.

// Declare schema version at the top of your config
schema-version "1.0"

server {
    // ...
}

Version Format

Schema versions use major.minor format:

VersionMeaning
1.0Initial stable schema
1.1Minor additions (backward compatible)
2.0Major changes (may require migration)

Compatibility Behavior

Config Version vs SentinelResult
Exact match✓ Loads normally
Config older but supported✓ Loads normally
Config newer than Sentinel⚠ Loads with warning (some features may not work)
Config older than minimum✗ Rejected with error
Invalid format✗ Rejected with error

Omitting Version

If schema-version is not specified, Sentinel assumes the current version. For production deployments, explicitly specifying the version is recommended:

// Explicit version (recommended for production)
schema-version "1.0"

server { /* ... */ }

This ensures configuration files remain compatible when upgrading Sentinel, and provides clear error messages if migration is needed.

Complete Example

// Sentinel Configuration
// Production API Gateway

schema-version "1.0"

server {
    worker-threads 0          // 0 = auto-detect CPU cores
    max-connections 10000
    graceful-shutdown-timeout-secs 30
}

listeners {
    listener "https" {
        address "0.0.0.0:443"
        protocol "https"
        tls {
            cert-file "/etc/sentinel/certs/server.crt"
            key-file "/etc/sentinel/certs/server.key"
            min-version "1.2"
        }
    }

    listener "admin" {
        address "127.0.0.1:9090"
        protocol "http"
    }
}

routes {
    route "api" {
        priority 100
        matches {
            path-prefix "/api/"
            method "GET" "POST" "PUT" "DELETE"
        }
        upstream "backend"
        agents "auth" "ratelimit"
    }

    route "health" {
        priority 1000
        matches {
            path "/health"
        }
        service-type "builtin"
        builtin-handler "health"
    }
}

upstreams {
    upstream "backend" {
        targets {
            target { address "10.0.1.1:8080" weight=3 }
            target { address "10.0.1.2:8080" weight=2 }
            target { address "10.0.1.3:8080" weight=1 }
        }
        load-balancing "weighted_round_robin"
        health-check {
            type "http"
            path "/health"
            interval-secs 10
            timeout-secs 5
        }
    }
}

agents {
    agent "auth" {
        type "auth"
        transport "unix_socket" {
            path "/var/run/sentinel/auth.sock"
        }
        timeout-ms 100
        failure-mode "closed"
    }

    agent "ratelimit" {
        type "rate_limit"
        transport "unix_socket" {
            path "/var/run/sentinel/ratelimit.sock"
        }
        timeout-ms 50
        failure-mode "open"
    }
}

limits {
    max-header-size-bytes 8192
    max-header-count 100
    max-body-size-bytes 10485760  // 10MB
}

Alternative Formats

Sentinel also supports JSON and TOML for programmatic generation:

JSON

{
  "server": {
    "worker_threads": 4,
    "max_connections": 10000
  },
  "listeners": [
    {
      "id": "http",
      "address": "0.0.0.0:8080",
      "protocol": "http"
    }
  ]
}

TOML

[server]
worker_threads = 4
max_connections = 10000

[[listeners]]
id = "http"
address = "0.0.0.0:8080"
protocol = "http"

File format is auto-detected by extension:

  • .kdl → KDL
  • .json → JSON
  • .toml → TOML

Multi-File Configuration

For complex deployments, split configuration across multiple files:

/etc/sentinel/
├── sentinel.kdl        # Main config (includes others)
├── routes/
│   ├── api.kdl
│   ├── static.kdl
│   └── admin.kdl
├── upstreams/
│   ├── backend.kdl
│   └── cache.kdl
└── agents/
    └── security.kdl

Use directory loading:

sentinel --config-dir /etc/sentinel/

Or explicit includes in your main config:

// sentinel.kdl
include "routes/*.kdl"
include "upstreams/*.kdl"
include "agents/*.kdl"

Validation

Validate configuration before applying:

# Check syntax and semantics
sentinel --config sentinel.kdl --validate

# Dry-run mode
sentinel --config sentinel.kdl --dry-run

Common validation errors:

ErrorCause
Route references unknown upstreamTypo in upstream name
No listeners definedMissing listeners block
Invalid socket addressWrong format (need host:port)
Duplicate route IDTwo routes with same name

Hot Reload

Sentinel supports configuration reload without restart:

# Send SIGHUP to reload
kill -HUP $(cat /var/run/sentinel.pid)

# Or use the admin endpoint
curl -X POST http://localhost:9090/admin/reload

Reload behavior:

  1. Parse new configuration
  2. Validate syntax and semantics
  3. If valid, atomically swap configuration
  4. If invalid, keep old configuration and log error

Next Steps