^[a-z][a-z0-9-]{0,30}$ and must be unique within the spec.
build or image
Each service either builds from your repo or pulls a prebuilt image — exactly one.
build
With no
target, slipway builds the last stage in your Dockerfile, exactly like docker build with no --target. That’s a common source of surprise: if your Dockerfile ends with a development or dev-envs stage, that’s the image you’ll deploy, and it’s the one that has to build. Name the stage you actually want to run.image
ports
Ports the container listens on. Omit ports and the service is a worker — internal-only, no URL, no readiness gate at cutover.
env
Environment variables, as a plain map:
${...} substitution syntax.
Variables slipway sets for you
Every service with a public port also gets these, set by the platform:
You can’t hardcode that hostname: it carries the environment-instance id, and every pull-request preview gets a different one. Read it from the environment instead. If you set either name yourself in
env, yours wins.
files
Project committed repo files into the container, read-only — the cluster-native counterpart of a Docker Compose bind mount, for config and seed files: a Postgres init.sql, an nginx.conf, a fixtures file. Each entry is <repo-path>:<container-path> — the source is a path in your repo relative to the spec file’s directory, the target an absolute path in the container.
subPath, so only that one file lands at the target — the rest of the directory (the image’s own contents) is untouched. A Compose ./init.sql:/docker-entrypoint-initdb.d/init.sql bind mount is translated to this automatically.
Constraints: small text files (each under ~1 MB), and the source must stay inside the repo (no absolute or .. paths). For data that must persist, or large/binary content, use a named volume instead.
depends_on
Sibling services that must be ready before this one starts — Compose’s service_healthy semantics. All services are created at once so images pull and volumes attach in parallel, but a service’s own process doesn’t start until every dependency passes its readiness probe. It waits instead of crash-looping. If a dependency never comes up within the deploy window, the deployment fails with the dependency named in the reason, rather than going live with a service that never started.
depends_on guarantees start ordering, not zero-downtime ordering (services run a single replica).
healthcheck
Three probe phases — set any subset:
startup— runs first and blocks the others until it passes. For slow-booting apps.readiness— gates traffic and gates cutover: a deploy isn’thealthyand its URL doesn’t go live until every public service is ready.liveness— runs continuously; failures restart the container.
healthcheck, slipway adds a default TCP readiness probe on its public port, so a URL only goes live once the app accepts connections. Declaring any healthcheck replaces that default.
Handlers
Each probe takes exactly one handler:Timing
All handlers accept the standard knobs —initialDelaySeconds, periodSeconds, timeoutSeconds, failureThreshold, and successThreshold (readiness/liveness only). Omit them to use sensible defaults.
For most web apps a single readiness probe is enough. Add startup only when boot takes more than ~30 seconds; add liveness only when you’ve seen the app deadlock in a way readiness doesn’t catch. A worker with no ports needs no probe — it’s ready as soon as it’s running.