Kedge accepts the Compose Specification as its source format for container applications. compose.yaml defines services, networks, volumes, configs, and secrets; Kedge deploys the project as one app. It also recognizes compose.yml, docker-compose.yaml, and docker-compose.yml, in that order.

This page documents the source format and supported fields. A single service does not need Compose; use native Dockerfile metadata or kedge up properties.

a runnable service

This is enough to publish a prebuilt server with bounded scale-to-zero:

~/compose-httpbin$ show compose.yaml
── compose.yaml
services:
  web:
    image: ghcr.io/mccutchen/go-httpbin:2.23.1
    ports: ["8080"]
    x-kedge:
      scale:
        min: 0
        max: 5
        concurrency: 8
        idle-cooldown: 30s

~/compose-httpbin$ kedge up

ports gives the service an HTTPS route; x-kedge.scale controls its autoscaled instances.

a complete small stack

name: myblog

services:
  web:
    build: .
    ports: ["8000"]
    environment:
      DATABASE_HOST: db
      DATABASE_PASSWORD_FILE: /run/secrets/db-password
    secrets: [db-password]
    depends_on:
      db: {condition: service_healthy}

  worker:
    build: .
    command: [python, worker.py]
    environment:
      DATABASE_HOST: db

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db-password
    secrets: [db-password]
    volumes: [pgdata:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s

volumes:
  pgdata:
    x-kedge: {size: 10GiB}

secrets:
  db-password:
    x-kedge: {generate: {bytes: 32}}

web and worker share one build. db is private and gets a persistent volume, so its service uses stable members. depends_on orders the first rollout; service_healthy waits for the in-guest healthcheck.

common Compose fields

area supported fields
process image, build, command, entrypoint, working_dir, user, stop_signal
configuration environment, env_file, configs, secrets, labels
serving ports, expose, healthcheck, depends_on
resources cpus, mem_limit, deploy.resources.limits, deploy.replicas
topology services, named volumes; networks within the limits below

Resource fields are limits, not reservations. See configuration and pricing & billing.

Published ports map to the app's HTTPS hostname, not a host port. expose is private. A portless service without a persistent volume is a worker kept at a floor of one. A healthcheck runs inside the guest and gates readiness. See network & domains for ingress behavior.

Kedge classifies every Compose field. Some local-container settings are superseded by the platform (restart, logging, init); unsupported or isolation-breaking fields fail with an explanation. Every set field is applied, superseded with an explanation, or rejected.

service x-kedge

services:
  web:
    build: .
    ports: ["8000"]
    x-kedge:
      scale:
        min: 0
        max: 50
        concurrency: 8
        idle-cooldown: 30s
      memory: 1GiB
      members: 0

Service x-kedge accepts the same application/service properties used throughout Kedge. Nested keys preserve the bare dotted name: scale.max above is the same property as KEDGE_SCALE_MAX, kedge.scale.max, and dev.kedge.scale.max.

Use fixed deploy.replicas or dynamic x-kedge.scale, not both. deploy.replicas counts stable members when the service has a persistent volume and pooled instances otherwise. A positive x-kedge.members value is an alternative member count, so do not set both. members: 0 can accompany deploy.replicas to select a fixed-size instance pool.

Runtime & scaling explains how these bounds, concurrency, and cooldown affect an instance pool.

volume x-kedge

field meaning
shared true gives pooled instances one filesystem; false gives each stable member its own persistent volume; omitted infers from usage
size logical storage limit for the sparse volume

One writable service at one effective replica infers shared: false. Several services mounting the same volume infer shared: true. A service that may scale past one instance must set the value explicitly. Anonymous mounts such as volumes: [/data] are private.

The persistent volumes guide covers image seeding, member identity, and retention. Shared data covers shared: true.

All service and volume values also appear in the unified configuration property reference, alongside their single-service and image equivalents.

networks

Compose normally supplies a project-scoped default network. Kedge instead joins every service to the reserved account network when networks is omitted. An explicit external network named kedge expresses the same attachment. Other declared networks are shown in the deploy plan and rejected.

See network & domains for DNS names.

secrets and configs

Compose secrets and configs are top-level resources that services receive as guest files. Kedge accepts repository file or inline content sources; secret targets default to /run/secrets/<name>. Compose environment and external sources are parsed but rejected until the account secret store is available.

x-kedge.generate.bytes adds a platform source: Kedge mints the value once, stores it outside Git, and preserves it across updates. See starter apps for a complete generated-secret example.

top-level x-kedge

field meaning
production-branch production branch; default main
inputs deploy-form interpolation fields with description, default, optional
auth app-user or workforce admission policy
static.fallback SPA fallback path for a service-less site
static.handler-excludes directories whose shebang files are not handlers

Unknown fields inside x-kedge are errors. Precedence and equivalent single-service, image, and handler declarations live in the configuration reference.

authentication

Top-level auth protects a static or handler tree and is the default for every service. A service-level x-kedge.auth replaces that default for the service. The app authentication guide defines the required and owner shorthands, structured path and workforce policies, login behavior, and identity delivery to HTML, handlers, and services.