Import a Docker Compose file
Turn a docker-compose.yml into Dekka services, managed databases and connections, see a report of what changed, and deploy it.
Dekka can read a docker-compose.yml and set up the same app as Dekka services. Containers that run your code become services, Postgres, Redis and MinIO containers become managed databases and buckets with connections, and the variables that pointed at those containers are rewritten to use the connections. A report lists what carried over, what changed to fit Dekka and what was left out, and nothing is created until you deploy the plan.
Import in the dashboard
- On a project's canvas, choose Add, then Template or dekka.yaml, and open the Docker Compose tab.
- Paste the file or choose Open a file, then choose Translate.
- Read the report. If any service has a
buildsection, choose the GitHub Repository and Branch to build it from. - Fill in any values the file asks for, choose Review changes, check the planned changes and deploy them.
The translation is a dekka.yaml blueprint, so you can also copy it, keep it in your repository and plan it again later.
What the report looks like
This is part of n8n's own Compose file for running with Postgres.
services:
postgres:
image: postgres:16
environment:
- POSTGRES_USER
- POSTGRES_PASSWORD
- POSTGRES_DB
volumes:
- db_storage:/var/lib/postgresql/data
n8n:
image: docker.n8n.io/n8nio/n8n
environment:
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY:?set an encryption key}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-Africa/Accra}
ports:
- 5678:5678
volumes:
- n8n_storage:/home/node/.n8n
depends_on:
- postgresThe report groups each note under Carried over as written, Changed to fit Dekka or Left out.
| Service | Level | Note |
|---|---|---|
| postgres | adjusted | Becomes a managed Postgres 16. Dekka creates the credentials and gives them to the services that use it. |
| postgres | applied | Its storage is managed, so the volume isn't needed. |
| n8n | adjusted | The image has no tag, so it uses docker.n8n.io/n8nio/n8n:latest. Pin a version to control upgrades. |
| n8n | applied | Served on port 5678 at a public dekka.cloud domain. |
| n8n | applied | Gets a 1 GB volume at /home/node/.n8n. Resize it in Dekka if it needs more. |
| n8n | adjusted | DB_POSTGRESDB_HOST now reads PGHOST from the connection. |
| n8n | adjusted | DB_POSTGRESDB_USER now reads PGUSER from the connection. |
| n8n | applied | Connected to postgres. |
The n8n service ends up with DB_POSTGRESDB_HOST set to ${{n8n.PGHOST}}, so it reads the managed database's host from its connection, and N8N_ENCRYPTION_KEY becomes a required value you enter before planning.
How Compose maps to Dekka
| In Compose | On Dekka |
|---|---|
A service with image and ports |
A web service running that image on the first published port, at a public address |
A service with image and only expose |
A web service on that port, reachable inside the environment only |
| A service with no ports | A worker |
build |
A service built from your GitHub repository with the Dockerfile builder, using context as the root directory and dockerfile, target and args as its settings |
postgres, postgis, pgvector or timescaledb images |
A managed PostgreSQL 16 or 17, matching the image's major version |
redis, valkey or keydb images |
A managed Redis with persistence on |
A minio image |
A Dekka bucket |
depends_on, links, or a variable naming a database container |
A connection from the service to that database |
command and entrypoint |
The start command |
environment |
Service variables |
The first volumes entry with a container path |
A 1 GB volume at that path |
healthcheck that requests http://localhost/... |
The health check path |
deploy.resources.limits.memory or mem_limit |
Memory, rounded to a size Dekka offers |
deploy.resources.limits.cpus or cpus |
vCPU, in steps of 0.25 |
deploy.replicas |
Replicas, unless the service has a volume |
restart |
The restart policy, with unless-stopped treated as always |
Variables that point at databases
Inside Compose, services find each other by container name, such as postgres:5432. On Dekka a connection gives the service its own credentials as variables, so the translation rewrites values that named a database container.
- A URL such as
DATABASE_URL=postgres://user:pass@db:5432/apporREDIS_URL=redis://cache:6379is dropped, because the connection sets that variable itself. - A variable whose value is the container's name, port, user, password or database, such as
DB_HOST=dborDB_PASSWORD=${POSTGRES_PASSWORD}, reads the matching connection variable instead, such as${{web.PGHOST}}or${{web.PGPASSWORD}}. - A URL or host variable that names another service, such as
API_URL=http://api:8000, uses that service's private domain,${{api.DEKKA_PRIVATE_DOMAIN}}. - A secret whose value is a placeholder, such as
APP_SECRET=replace-me-with-a-random-string, gets a random value that Dekka generates once. - Variables Dekka sets itself, such as
PORT, keep Dekka's value.
Values from your shell
Compose fills ${VAR} from your shell or a .env file, which Dekka can't see, so the translation turns them into values you enter when you plan.
| In Compose | On Dekka |
|---|---|
${VAR:-default} or ${VAR-default} |
The default, written into the variable |
${VAR}, $VAR or a bare VAR in a list |
An optional value you can enter, left unset if you don't |
${VAR:?message} or ${VAR?message} |
A required value, with the message as its description |
$$ |
A literal $ |
Names that look like secrets, such as ones containing PASSWORD, TOKEN or KEY, are entered as secrets. Commands and build arguments can't read these values, so a command or build argument that uses one without a default is left out and the report says so.
Services that build from source
A service with a build section is built from a GitHub repository you choose, with the Dekka GitHub App connected. Every such service in the file uses the same repository and branch, and its context becomes its root directory. Planning without a repository answers 422 repository_required with the services that need one. A remote build context, such as a Git URL, isn't fetched, and dockerfile_inline isn't read, so commit the Dockerfile to the repository instead.
What's left out
| Compose setting | What to do instead |
|---|---|
| More than one published port | Dekka serves one port per service. Split the other ports into their own services. |
| UDP ports | Dekka serves HTTP and TCP only. |
| A second volume on a service | A service has one volume. Combine the paths under one directory. |
env_file |
Add those variables to the service in Dekka. |
secrets and configs |
Add secrets as secret variables, and put config files in the image or a volume. |
extends |
Copy the settings into the service. |
networks and network_mode |
Every service shares the environment's private network, so nothing is needed. |
profiles |
Every service is included. Remove the ones you don't want before importing. |
privileged, cap_add, devices, pid, ipc, sysctls and security_opt |
Services can't run with host-level access. |
working_dir and user |
Set them in the image's Dockerfile. |
extra_hosts, dns and tmpfs |
Not available. |
| A health check that isn't an HTTP request | Dekka checks GET / instead, or set a health check path in the service's settings. |
Settings that make no difference on Dekka, such as container_name, labels, logging and stop_signal, are ignored without a note.
Import with the API
POST /v1/compose/translate returns the blueprint, the report, the resources it would create, the values it needs and whether it needs a repository, and changes nothing.
curl https://api.dekka.cloud/v1/compose/translate \
-H "Authorization: Bearer $DEKKA_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile content docker-compose.yml '{content: $content}')"POST /v1/environments/{id}/compose/plan translates the file again and plans it into an environment, returning a changeset. Pass the values it asks for in inputs, and the repository for any build services.
curl https://api.dekka.cloud/v1/environments/$ENV_ID/compose/plan \
-H "Authorization: Bearer $DEKKA_API_KEY" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile content docker-compose.yml '{
content: $content,
inputs: {N8N_ENCRYPTION_KEY: "your-32-character-key"},
repository: {full_name: "acme/shop", branch: "main"}
}')"Deploy the changeset with its id once you've read the changes.
curl -X POST https://api.dekka.cloud/v1/changesets/$CHANGESET_ID/deploy \
-H "Authorization: Bearer $DEKKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"confirm": true}'A file that isn't valid YAML, has no services or is larger than 200 KB answers 422 invalid_compose. A required value left out answers 422 missing_input with the missing keys, and going over your plan's limits answers 403 entitlement_exceeded.