Compose stacks
Run your repo's own docker-compose.yml in a devbox — the app plus its databases and queues. Which features work, which are rejected, and why.
If your repo has a docker-compose.yml, a devbox runs that file. Sokko does
not translate it into something else and does not ask you to maintain a second
copy of it. Your app, its Postgres, its Redis and its worker all come up
together, exactly as they do on your laptop.
This is the mode to use when your app needs other services next to it. If it is
a single process — a Worker, a Next.js app, a FastAPI service — use a run:
command instead. It starts faster and builds nothing. See
sokko.devbox.yml.
Getting started
Nothing to configure. A docker-compose.yml or compose.yaml at your repo root
is picked up on the first deploy, images are built in the devbox, and volumes
start empty — your own migrations and entrypoints seed them.
Two things you may want to say, in a sokko.devbox.yml beside it:
compose_file: deploy/compose.yml # only if it is not at the repo root
expose: web:3000 # which service the preview URL points atSokko picks the preview service on its own when exactly one service publishes
ports. With several, it stops and asks — expose: is the answer.
Supported keys
Devboxes run compose against an allow-list. Anything not on this list is rejected by name, with the fix in the error. That is deliberate: several perfectly ordinary compose keys let a container read things it should not, and listing the safe ones is the only version of this that stays safe as compose grows.
Top level: services, volumes, networks, version, name, and any
x- extension.
Per service:
| Key | Notes |
|---|---|
image | pulled from any public registry |
build | context, dockerfile, args, target |
command, entrypoint | |
environment, env_file | env_file paths must be inside the repo |
ports, expose | |
depends_on | start order is honoured, including condition: service_healthy |
healthcheck | Sokko runs it and waits on the result before starting dependents |
restart | |
working_dir, user | |
stop_grace_period | |
volumes | named volumes, and bind paths inside the repo (./data) |
networks | between your own services |
Volume definitions take name and labels. Network definitions take
name, labels, internal and driver. Long-form volume entries take type,
source, target and read_only.
What gets rejected
| Rejected | Why |
|---|---|
Absolute or ~ bind mounts | A devbox has no host filesystem to share. Use a named volume, or a path inside your repo. |
external: true volumes, driver_opts | Both reach outside the devbox. |
pid, ipc, userns_mode, network_mode: container:, devices, cgroup_parent, security_opt, privileged | These weaken the wall between your stack and the machine running it. |
| Anything else not listed above | Unknown means rejected, by design. |
Service names must start with a letter or digit and contain only letters,
digits, _, . and -.
You will see these as COMPOSE_UNSUPPORTED, naming the exact key. Removing it
is usually enough — a devbox is a preview environment, and the rejected keys are
almost always there for production or for a developer's own machine.
Images and builds
- Builds happen inside the devbox. There is no registry to push to and no build service to configure.
- Layers are cached on the devbox's disk, so redeploying the same branch is incremental, and the cache survives an idle stop.
- Public base images pull over a shared address. A very busy day on Docker Hub
can produce
REGISTRY_RATE_LIMITED— wait for the window to pass, or use a base image from a registry that does not rate-limit anonymous pulls. - Disk fills up over many deploys. Sokko cleans up superseded images after each
successful deploy, but a stack with very large images on the smaller plans can
still hit
DISK_FULL. Destroy and recreate the devbox to get a clean disk.
Databases and data
Every devbox starts with empty volumes. Your compose file's own Postgres, MySQL or Redis comes up fresh, and your migrations and seed scripts run against it the way they do locally.
Sokko does not copy production data into a devbox. If you need realistic data, seed it from your repo — a seed script in the compose stack is the shape that works, because it comes back automatically on the next devbox too.
Credentials committed inside a compose file (POSTGRES_PASSWORD: dev) are fine
here: the database is only reachable from inside that devbox, and nothing but
your exposed service is reachable from outside. Real secrets — API keys, tokens
for third-party services — belong in Repo secrets.
Which service the preview shows
Only one service is served at the preview URL. Sokko picks it in this order:
expose:insokko.devbox.yml—web:3000, or justweb- the only service that publishes
ports: - otherwise the deploy fails with
PORT_DETECT_FAILED, listing the candidates
Your other services keep talking to each other by service name inside the devbox, exactly as in compose. They are simply not published to the internet.
The exposed service must bind 0.0.0.0 inside its container. A server on 127.0.0.1 is reachable
from nothing but itself, and the deploy will time out waiting for it.
A Dockerfile with no compose file
A repo with a lone Dockerfile and nothing else works too: Sokko builds the
image and runs it as a one-service stack. If the Dockerfile declares EXPOSE,
that port is used; otherwise PORT is set and the standard port is assumed.
This is the last thing Sokko tries, on purpose — building an image is the slowest way to preview a repo that also has a dev server, and nearly every repo has a Dockerfile for some other reason.
sokko.devbox.yml
The optional file that tells Sokko how to run your repo — the command, the port, and the health check. Most repos never need it; here is what it does when you want one.
Secrets and environment
Where a devbox's environment variables come from, which layer wins, and where real secrets belong.