# Migrating from Docker Compose to PandaStack (Without Breaking Everything)
Docker Compose is a genuinely great tool for development. It's also one of those things that ends up in production because it works, and nobody questions it until the server dies at 2am and you're SSHing in to restart containers by hand.
This guide walks through migrating a typical Compose stack — app + database + Redis — to PandaStack.
The Starting Point
A typical docker-compose.yml for a Node.js app:
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
db:
image: postgres:15
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: myapp
redis:
image: redis:7-alpine
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:Step 1: Move the Database to PandaStack Managed PostgreSQL
Instead of running Postgres in a container, provision a managed instance:
Dashboard → Databases → New Database → PostgreSQL
You'll get a connection URL like:
postgresql://user:password@postgres.pandastack.io:5432/myappThis database has automated backups, connection pooling, and doesn't go down when your app server restarts. That alone is worth the migration.
Step 2: Move Redis to PandaStack Managed Redis
Same process: Databases → New Database → Redis
You'll get a REDIS_URL to use in your app's environment variables.
Step 3: Deploy the App Container
Your Dockerfile stays exactly the same. PandaStack builds from it directly:
- 1Dashboard → Projects → New Project → Container App
- 2Connect your GitHub repo
- 3Add environment variables:
- DATABASE_URL — from step 1
- REDIS_URL — from step 2
- Any other app-specific vars
- 1Deploy
Step 4: Handle Multiple Services
If your Compose file has multiple app services (e.g., a web process and a worker process), deploy each as a separate PandaStack project:
myapp-web— runsnpm start(web server)myapp-worker— runsnpm run worker(background jobs)
Both share the same database and Redis — just use the same DATABASE_URL and REDIS_URL in both projects.
Step 5: Replace Volume Mounts for File Storage
If your app writes files to a volume (uploads, generated PDFs, etc.), volumes don't work the same way in containers-as-a-service. Options:
- 1S3-compatible storage — use AWS S3, Cloudflare R2, or similar. Store the bucket credentials as env vars. PandaStack doesn't prevent this.
- 2Keep it stateless — for most apps, files shouldn't live in the container anyway. This is a good time to fix that.
Step 6: Cut Over DNS
Once the PandaStack deployment is verified:
- 1Lower your DNS TTL to 60 seconds, 24 hours before the cutover
- 2Test thoroughly on the PandaStack URL (
https://myapp.pandastack.io) - 3Update your DNS CNAME to point to PandaStack
- 4Watch logs for 30 minutes
What You Gain
- No more SSH sessions to restart containers
- Automatic database backups (PandaStack managed databases)
- Rolling deploys instead of
docker-compose pull && docker-compose up -d - Real metrics and alerts
- HTTPS out of the box (no Let's Encrypt config to maintain)
Common Gotchas
Inter-service communication: In Compose, services talk to each other by service name (http://app:3000). On PandaStack, each project has its own subdomain. Update any internal URLs to use environment variables.
Init containers: If you had a custom init step that ran database migrations before the app started, handle that with a startup script or a one-time PandaStack cronjob run after deploy.
Healthchecks: Add a GET /health endpoint to your app that returns 200. PandaStack uses this to verify the container started successfully.
Full docs: [docs.pandastack.io](https://docs.pandastack.io). CLI: npm install -g @pandastack/cli.