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

  1. 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.
  2. 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.
  3. 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.
  4. 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 build becomes 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, and dockerfile and target are kept.
  • A service that only names an image needs 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

DirectiveTreatmentWhat happens
nameCarried overUsed as the migration's stack name.
servicesCarried overEach service becomes an app, worker, managed database or proxy entry.
volumesPartly carried overNamed volumes become Nouva volumes on the one service that mounts them; database volumes are migrated through a verified import. External volumes are never claimed.
networksPartly carried overEvery service in a project shares one private network, so Compose networks are merged into it. External networks and network drivers are not carried over.
versionHandled by NouvaObsolete in the Compose specification and not needed by Nouva.
secretsNot carried overCompose secrets are files on the source host. Add the values as service variables instead.
configsNot carried overCompose configs are files on the source host. Bake them into the image or set them as variables.
includeNot carried overIncluded Compose files are not read. Paste a single merged file instead.
modelsNot carried overAI model definitions are not supported.

Service directives

A directive not listed here is reported as not carried over.

DirectiveTreatmentWhat happens
imageCarried overDatabase images become managed databases with a matching version. Other images need a GitHub repository to build from, because Nouva builds every app from source.
buildCarried overBecomes 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.
commandPartly carried overBecomes 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.
entrypointPartly carried overPrepended to a worker's start command. Apps start with their image's own entrypoint.
environmentCarried overBecomes 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_fileNot carried overEnv files live on the source host and are not uploaded. Supply those variables when staging.
portsPartly carried overAn 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.
exposeCarried overUsed as the app's port when ports is not set.
volumesPartly carried overOne 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_onCarried overDecides the order resources are staged in. Nouva does not hold a service back until its dependencies are healthy, so apps must retry their connections.
healthcheckPartly carried overBecomes 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.
deployPartly carried overresources.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_limitCarried overBecomes the memory limit.
cpusCarried overBecomes the CPU limit.
scalePartly carried overBecomes a worker's replica count. Apps run a single replica.
networksPartly carried overServices join the project's private network. Aliases and fixed addresses are not carried over.
linksHandled by NouvaEvery service in a project can already reach the others on the private network.
restartHandled by NouvaNouva supervises and restarts every container it runs.
container_nameHandled by NouvaNouva names containers itself.
labelsHandled by NouvaContainer labels are not carried over. Routing labels (for example Traefik's) are replaced by Nouva domains.
loggingHandled by NouvaNouva collects container logs itself.
stop_signalHandled by NouvaNouva stops containers with the image's default signal.
stop_grace_periodHandled by NouvaNouva uses its own stop timeout.
ttyHandled by NouvaNot needed for services Nouva runs.
stdin_openHandled by NouvaNot needed for services Nouva runs.
pull_policyHandled by NouvaNouva builds images itself, so there is nothing to pull.
mem_reservationHandled by NouvaNouva reserves capacity from the limit you set.
memswap_limitHandled by NouvaSet a swap allowance in the service's resource settings if you need one.
mem_swappinessHandled by NouvaNot configurable per service.
cpu_sharesHandled by NouvaNouva sets CPU limits rather than relative shares.
cpu_quotaHandled by NouvaNouva sets CPU limits from cpus or deploy.resources.limits.
cpu_periodHandled by NouvaNouva sets CPU limits from cpus or deploy.resources.limits.
cpusetHandled by NouvaContainers are not pinned to CPUs.
annotationsHandled by NouvaContainer annotations are not carried over.
developHandled by NouvaCompose Watch is a local development feature.
attachHandled by NouvaOnly affects docker compose up output.
hostnameNot carried overNouva assigns each service its internal hostname.
domainnameNot carried overNouva assigns each service its internal hostname.
working_dirNot carried overSet the working directory with WORKDIR in the Dockerfile.
userNot carried overSet the user with USER in the Dockerfile.
privilegedNot carried overPrivileged containers are never run.
network_modeNot carried overServices always run on the project's private network, never host.
pidNot carried overSharing a PID namespace is not supported.
ipcNot carried overSharing an IPC namespace is not supported.
utsNot carried overSharing a UTS namespace is not supported.
userns_modeNot carried overUser namespace settings are not supported.
devicesNot carried overHost devices are never passed through.
device_cgroup_rulesNot carried overHost devices are never passed through.
gpusNot carried overGPU access is not supported.
cap_addNot carried overAdditional Linux capabilities are never granted.
cap_dropNot carried overCapabilities are managed by Nouva.
security_optNot carried overSecurity options are managed by Nouva.
sysctlsNot carried overKernel parameters are not set per container.
ulimitsNot carried overPer-container ulimits are not supported.
cgroupNot carried overCgroup namespace settings are not supported.
cgroup_parentNot carried overCgroup placement is managed by Nouva.
runtimeNot carried overOnly the default container runtime is used.
isolationNot carried overOnly the default isolation is used.
extra_hostsNot carried overCustom host entries are not supported. Use a DNS name instead.
dnsNot carried overCustom DNS servers are not supported.
dns_optNot carried overCustom DNS options are not supported.
dns_searchNot carried overCustom DNS search domains are not supported.
mac_addressNot carried overFixed MAC addresses are not supported.
external_linksNot carried overContainers outside the project cannot be linked.
volumes_fromNot carried overSharing another container's volumes is not supported.
extendsNot carried overInherited services are not resolved. Paste the merged service instead.
profilesNot carried overProfiles are not evaluated: every service in the file is planned. Remove the services you do not want to migrate.
secretsNot carried overCompose secrets are files on the source host. Add them as variables.
configsNot carried overCompose configs are files on the source host. Bake them into the image.
tmpfsHandled by NouvaContainer filesystems are already writable and discarded on redeploy.
shm_sizeNot carried overThe shared memory size cannot be changed.
read_onlyNot carried overRead-only root filesystems are not supported.
initNot carried overAn init process cannot be injected. Add one to the image if you need it.
platformNot carried overImages are built for the server's own platform.
oom_kill_disableNot carried overThe out-of-memory killer cannot be disabled.
oom_score_adjNot carried overOut-of-memory priority cannot be changed.
pids_limitHandled by NouvaNouva applies its own process limit.
storage_optNot carried overStorage driver options are not supported.
blkio_configNot carried overBlock I/O limits are not supported.
group_addNot carried overSupplementary groups are not supported.
post_startNot carried overLifecycle hooks are not supported.
pre_stopNot carried overLifecycle hooks are not supported.
credential_specNot carried overCredential specs are not supported.
use_api_socketNot carried overThe Docker API socket is never exposed to services.
modelsNot carried overAI model bindings are not supported.
providerNot carried overProvider services are not supported.