> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slipway.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Compose

> Deploy a committed docker-compose file as-is — no slipway.yaml required.

If your repo already has a `docker-compose` file, slipway can deploy it directly. Slipway reads and converts it on every deploy, the same way it reads a `slipway.yaml`. Nothing is written back to your repo, and conversion needs no extra GitHub permissions — slipway stays read-only on your code.

A committed `slipway.yaml` takes precedence over Compose unless you explicitly pin a Compose file.

## Getting a Compose repo deploying

1. **Add the repo to an [environment](/environments/overview)** from its repo page.
2. **Pick the Compose file** if the repo has more than one (e.g. `docker-compose.dev.yml` vs `.prod.yml`). Slipway remembers the choice.
3. **Fill in the values** your file references. The [Secrets Manager](/slipway-yaml/secrets-and-variables#the-secrets-manager) shows exactly which `${NAME}` references are still missing.
4. **Deploy.** Every push reconverts the current file and deploys it.

## What translates

| Docker Compose                                 | slipway                                   |
| ---------------------------------------------- | ----------------------------------------- |
| `build` (context, dockerfile, args)            | `build`                                   |
| `image`                                        | `image`                                   |
| `ports` (published)                            | `ports` — one is marked public            |
| `expose`                                       | `ports` — internal only                   |
| `environment`                                  | `env`                                     |
| `healthcheck`                                  | `healthcheck`                             |
| `command`, `working_dir`                       | `command`, `workdir`                      |
| `depends_on`                                   | `depends_on` — waits on readiness         |
| named-volume mount (`pgdata:/path`)            | `volumes` — provisioned + snapshot-seeded |
| committed-file bind mount (`./init.sql:/path`) | `files` — projected read-only             |

**Named volumes** are provisioned and snapshot-seeded per preview (see [Volumes](/slipway-yaml/volumes)). A **bind mount of a committed repo file** — the classic `./init.sql:/docker-entrypoint-initdb.d/init.sql` — is projected into the container read-only (see [`files`](/slipway-yaml/services#files)), so init scripts and config files work unchanged.

## What's dropped

* **Anonymous volumes, host-path bind mounts (`/var/run/...`), networks, profiles, `deploy`** — ignored. A bind mount whose source is a committed repo file is projected (above); one that points at a host path or `..` outside the repo can't map onto a tenant pod and is dropped.
* **Literal-looking secrets** — an `environment` value whose key looks sensitive (`PASSWORD`, `TOKEN`, `SECRET`, a connection string) becomes a `${secret.NAME}` reference instead of landing in the spec. Set the real value in the Secrets Manager.
* **Database / cache services** (`postgres`, `redis`, …) run as stateless containers unless backed by a named volume. For real data, point your app at an external provider via a [secret](/slipway-yaml/secrets-and-variables).

## `${VAR}` references

Write Compose interpolations exactly as you do locally — the same `${VAR}` resolves on slipway, **secret store first, then variable store**, each scoped environment → org. Shell modifiers work too: `${VAR:?required}` must resolve, `${VAR:-default}` falls back, `${VAR:+alt}` uses the alternate when set. Slipway lists every referenced key and seeds each as a variable or secret by name; flip a row's type if the guess is wrong.

## `x-slipway` overrides

For the few things Compose can't express, add an `x-slipway` block to a service — `docker compose` ignores it:

```yaml theme={"system"}
services:
  api:
    build: .
    ports: ["8080:8080", "9090:9090"]
    x-slipway:
      public_port: 9090        # which port gets the public URL
      domain: api.acme.com     # a verified custom domain
      source: build            # force build vs pull when ambiguous
```

Most repos need none of this — the defaults guess the public port, and `depends_on` / volumes / `${VAR}` all work without annotation.
