Running Nanosync with Docker
The nanosync Docker image packages the single binary with no external runtime dependencies. It’s the same binary as the direct install — Docker just controls the environment.
Pull the image
docker pull ghcr.io/nanosyncorg/nanosync:latest
Pin to a specific version in production:
docker pull ghcr.io/nanosyncorg/nanosync:0.9.2
Available tags: latest (latest stable), edge (main branch tip), and version tags like 0.9.2. Check GitHub Container Registry for the full list.
Quick stream — no config file
Run a one-shot stream to stdout without mounting any config:
docker run --rm ghcr.io/nanosyncorg/nanosync:latest \
stream \
--source "postgres://user:pass@host.docker.internal:5432/mydb" \
--tables "public.orders"
Use host.docker.internal to reach a database running on the host machine. On Linux, pass --add-host=host.docker.internal:host-gateway if your Docker version doesn’t resolve it automatically.
With config files
Mount a directory containing your YAML files:
docker run --rm \
-v $(pwd)/config:/config \
-e PG_PASSWORD=secret \
-p 7600:7600 \
ghcr.io/nanosyncorg/nanosync:latest \
start --config /config/server.yaml
The container exposes port 7600 for the REST API and web UI. All nanosync commands that accept --config or --file take paths inside the container — mount your config directory to a predictable path like /config.
Secrets stay out of the image: pass them as environment variables with -e and reference them in YAML using ${env:VAR_NAME}.
Docker Compose for local development
A complete local setup with nanosync and a Postgres database configured for logical replication:
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: mydb
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
ports:
- "5432:5432"
command: postgres -c wal_level=logical
nanosync:
image: ghcr.io/nanosyncorg/nanosync:latest
depends_on:
- postgres
volumes:
- ./config:/config
- nanosync-data:/var/lib/nanosync
environment:
PG_PASSWORD: dev
ports:
- "7600:7600"
command: start --config /config/server.yaml
volumes:
nanosync-data:
Start both services:
docker compose up
The wal_level=logical flag in the Postgres command is required for CDC. The named volume nanosync-data persists state between container restarts — without it, nanosync loses its checkpoint on every docker compose down.
In a separate terminal, apply your pipeline definitions:
nanosync apply --host localhost:7600 --file pipelines.yaml
Or, if you don’t have nanosync installed locally, run it through the same container:
docker compose exec nanosync \
nanosync apply --file /config/pipelines.yaml
Applying pipelines to a running container
Use --host to point the CLI at a remote or containerized nanosync server:
nanosync apply --host localhost:7600 --file pipelines.yaml
All other commands that interact with a running server accept --host the same way:
nanosync monitor --host localhost:7600
nanosync pipeline status --host localhost:7600 orders-pipeline
nanosync pipeline resume --host localhost:7600 orders-pipeline
Production image considerations
In production, avoid latest — pin to an explicit version tag so deploys are reproducible. Use a multi-stage build or a separate image pull step in your CI pipeline to bake the image into your deployment artifact before promoting it.
The container runs as a non-root user by default. If you mount host directories, ensure the directory is owned by UID 65532 (the nonroot user inside the image), or use a named volume instead.
Use a named Docker volume for the nanosync data directory (/var/lib/nanosync) in production. Without it, the state store (SQLite checkpoints, schema history) is lost on container restart and nanosync will re-snapshot all tables from scratch on the next start.