Documentation
Migrate from Docker Compose
Turn an existing docker-compose.yml into a reviewable plan, stage the Nouva services next to the running stack, and cut over with a checklist you control.
What this is, and what it is not
nouva reads a documented subset of the Compose specification and maps it onto one project on your one server. It is a migration path, not a Compose runtime: Nouva never runs your Compose file, never adopts running containers in place, and never stops your source stack for you. Anything outside the subset is listed in the plan with the reason it is not carried over.
The four steps
- Plan. Paste or upload the file (up to 256 KiB) from the new-project dialog with Import from Docker Compose, or send it to
POST /v1/compose-migrations/preview. Previewing only parses the file. Variable values are never shown back, and${VAR}references are listed by name so you can supply them when staging. Saving the plan keeps an encrypted copy of the file with the migration until the source stack is retired. - Check the host. Before staging, Nouva compares the plan with what already runs on your server (ports 80 and 443, other published ports, containers, volumes, and free capacity), without changing anything.
- Stage. On your explicit approval, each app, worker, and database is created through the same paths as the dashboard, one at a time and databases first. You create or skip each one, pick the repository an app or worker is built from, and supply any values the file does not hold. Those values go to the new service only. The source containers keep running and keep their data. A failed step can be retried.
- Move data and traffic. PostgreSQL and Redis data moves through a verified database importinto the staged database, which then needs the import applied or a recorded reason for leaving its data behind. MySQL and MongoDB data is moved by hand, and you confirm it by marking that database's checklist step. A per-migration checklist covers backups, write freezes, DNS, verification, and how to roll back each step. You mark each item yourself, and you stop the source stack yourself: it is retired last. Completing the migration deletes the stored Compose file.
How services map
- A service with
buildbecomes an app when it publishes or exposes a port, and a worker otherwise. A service that a reverse proxy depends on is an app even without a port, with a warning to confirm the port it listens on. Its build context becomes the build root in the repository you pick, anddockerfileandtargetare kept. - A service that only names an
imageneeds the repository it is built from, since nouva builds from GitHub. - Official database images become managed databases on the closest supported version:PostgreSQL 18, 17, 16, 15; MySQL 8.4, 8.0; MongoDB 8.0, 7.0; Redis 7.4, 7.2, 7.0. When the source runs a newer version than any of these, its data cannot be imported, so the plan has it moved by hand.
- Reverse proxies such as nginx, Traefik, and Caddy stay on the source; nouvaserves ports 80 and 443 through its own Traefik.
- Connection variables that point at a Compose database service are rewritten to the managed database's reference variables, so credentials are never copied. A URL that selects a Redis index, another database, or a query option keeps that part around the host, port, and credential references, and is flagged for review. Only well-known connection options such as sslmode or replicaSet are kept; a URL with any other option is carried over unchanged for you to rewrite.
- Named volumes become a volume on the one service that mounts them and start empty. Database volumes move through the import instead, and external volumes are never claimed.
Top-level directives
| Directive | Treatment | What happens |
|---|---|---|
name | Carried over | Used as the migration's stack name. |
services | Carried over | Each service becomes an app, worker, managed database or proxy entry. |
volumes | Partly carried over | Named volumes become Nouva volumes on the one service that mounts them; database volumes are migrated through a verified import. External volumes are never claimed. |
networks | Partly carried over | Every service in a project shares one private network, so Compose networks are merged into it. External networks and network drivers are not carried over. |
version | Handled by Nouva | Obsolete in the Compose specification and not needed by Nouva. |
secrets | Not carried over | Compose secrets are files on the source host. Add the values as service variables instead. |
configs | Not carried over | Compose configs are files on the source host. Bake them into the image or set them as variables. |
include | Not carried over | Included Compose files are not read. Paste a single merged file instead. |
models | Not carried over | AI model definitions are not supported. |
Service directives
A directive not listed here is reported as not carried over.
| Directive | Treatment | What happens |
|---|---|---|
image | Carried over | Database images become managed databases with a matching version. Other images need a GitHub repository to build from, because Nouva builds every app from source. |
build | Carried over | Becomes a Dockerfile build from the repository you pick, with the context as build root (or the folder it shares with a Dockerfile outside it) and the same Dockerfile and target. |
command | Partly carried over | Becomes a worker's start command. The plan shows only its program, subcommands, option names and variable names, with every other word hidden; staging runs it as Compose would, with ${VAR} substituted from the values you supply. Apps start with their image's own command, so set CMD in the Dockerfile instead. |
entrypoint | Partly carried over | Prepended to a worker's start command. Apps start with their image's own entrypoint. |
environment | Carried over | Becomes service variables. Values are never shown back; ${VAR} references are listed so you can supply them, and connection strings pointing at a migrated database become reference variables. |
env_file | Not carried over | Env files live on the source host and are not uploaded. Supply those variables when staging. |
ports | Partly carried over | An app's first TCP container port becomes its PORT, routed over HTTPS on 80/443. Additional ports, UDP ports and fixed host ports are not published. |
expose | Carried over | Used as the app's port when ports is not set. |
volumes | Partly carried over | One named volume per app or worker becomes a Nouva volume at the same path. Bind mounts of host paths, external volumes, extra volumes and volumes shared between services are not carried over. |
depends_on | Carried over | Decides the order resources are staged in. Nouva does not hold a service back until its dependencies are healthy, so apps must retry their connections. |
healthcheck | Partly carried over | Becomes a worker's health check command, shown masked in the plan like command. Apps are probed on their HTTP port and databases are health-checked by Nouva, so theirs are not used. |
deploy | Partly carried over | resources.limits becomes CPU and memory limits and replicas a worker's replica count (at least one: skip a service kept at zero). Placement, update and restart policies are managed by Nouva. |
mem_limit | Carried over | Becomes the memory limit. |
cpus | Carried over | Becomes the CPU limit. |
scale | Partly carried over | Becomes a worker's replica count. Apps run a single replica. |
networks | Partly carried over | Services join the project's private network. Aliases and fixed addresses are not carried over. |
links | Handled by Nouva | Every service in a project can already reach the others on the private network. |
restart | Handled by Nouva | Nouva supervises and restarts every container it runs. |
container_name | Handled by Nouva | Nouva names containers itself. |
labels | Handled by Nouva | Container labels are not carried over. Routing labels (for example Traefik's) are replaced by Nouva domains. |
logging | Handled by Nouva | Nouva collects container logs itself. |
stop_signal | Handled by Nouva | Nouva stops containers with the image's default signal. |
stop_grace_period | Handled by Nouva | Nouva uses its own stop timeout. |
tty | Handled by Nouva | Not needed for services Nouva runs. |
stdin_open | Handled by Nouva | Not needed for services Nouva runs. |
pull_policy | Handled by Nouva | Nouva builds images itself, so there is nothing to pull. |
mem_reservation | Handled by Nouva | Nouva reserves capacity from the limit you set. |
memswap_limit | Handled by Nouva | Set a swap allowance in the service's resource settings if you need one. |
mem_swappiness | Handled by Nouva | Not configurable per service. |
cpu_shares | Handled by Nouva | Nouva sets CPU limits rather than relative shares. |
cpu_quota | Handled by Nouva | Nouva sets CPU limits from cpus or deploy.resources.limits. |
cpu_period | Handled by Nouva | Nouva sets CPU limits from cpus or deploy.resources.limits. |
cpuset | Handled by Nouva | Containers are not pinned to CPUs. |
annotations | Handled by Nouva | Container annotations are not carried over. |
develop | Handled by Nouva | Compose Watch is a local development feature. |
attach | Handled by Nouva | Only affects docker compose up output. |
hostname | Not carried over | Nouva assigns each service its internal hostname. |
domainname | Not carried over | Nouva assigns each service its internal hostname. |
working_dir | Not carried over | Set the working directory with WORKDIR in the Dockerfile. |
user | Not carried over | Set the user with USER in the Dockerfile. |
privileged | Not carried over | Privileged containers are never run. |
network_mode | Not carried over | Services always run on the project's private network, never host. |
pid | Not carried over | Sharing a PID namespace is not supported. |
ipc | Not carried over | Sharing an IPC namespace is not supported. |
uts | Not carried over | Sharing a UTS namespace is not supported. |
userns_mode | Not carried over | User namespace settings are not supported. |
devices | Not carried over | Host devices are never passed through. |
device_cgroup_rules | Not carried over | Host devices are never passed through. |
gpus | Not carried over | GPU access is not supported. |
cap_add | Not carried over | Additional Linux capabilities are never granted. |
cap_drop | Not carried over | Capabilities are managed by Nouva. |
security_opt | Not carried over | Security options are managed by Nouva. |
sysctls | Not carried over | Kernel parameters are not set per container. |
ulimits | Not carried over | Per-container ulimits are not supported. |
cgroup | Not carried over | Cgroup namespace settings are not supported. |
cgroup_parent | Not carried over | Cgroup placement is managed by Nouva. |
runtime | Not carried over | Only the default container runtime is used. |
isolation | Not carried over | Only the default isolation is used. |
extra_hosts | Not carried over | Custom host entries are not supported. Use a DNS name instead. |
dns | Not carried over | Custom DNS servers are not supported. |
dns_opt | Not carried over | Custom DNS options are not supported. |
dns_search | Not carried over | Custom DNS search domains are not supported. |
mac_address | Not carried over | Fixed MAC addresses are not supported. |
external_links | Not carried over | Containers outside the project cannot be linked. |
volumes_from | Not carried over | Sharing another container's volumes is not supported. |
extends | Not carried over | Inherited services are not resolved. Paste the merged service instead. |
profiles | Not carried over | Profiles are not evaluated: every service in the file is planned. Remove the services you do not want to migrate. |
secrets | Not carried over | Compose secrets are files on the source host. Add them as variables. |
configs | Not carried over | Compose configs are files on the source host. Bake them into the image. |
tmpfs | Handled by Nouva | Container filesystems are already writable and discarded on redeploy. |
shm_size | Not carried over | The shared memory size cannot be changed. |
read_only | Not carried over | Read-only root filesystems are not supported. |
init | Not carried over | An init process cannot be injected. Add one to the image if you need it. |
platform | Not carried over | Images are built for the server's own platform. |
oom_kill_disable | Not carried over | The out-of-memory killer cannot be disabled. |
oom_score_adj | Not carried over | Out-of-memory priority cannot be changed. |
pids_limit | Handled by Nouva | Nouva applies its own process limit. |
storage_opt | Not carried over | Storage driver options are not supported. |
blkio_config | Not carried over | Block I/O limits are not supported. |
group_add | Not carried over | Supplementary groups are not supported. |
post_start | Not carried over | Lifecycle hooks are not supported. |
pre_stop | Not carried over | Lifecycle hooks are not supported. |
credential_spec | Not carried over | Credential specs are not supported. |
use_api_socket | Not carried over | The Docker API socket is never exposed to services. |
models | Not carried over | AI model bindings are not supported. |
provider | Not carried over | Provider services are not supported. |