# Managing Dev, Staging, and Production on PandaStack
Most deployment guides show you how to go from zero to production. They skip the part where you need staging to test breaking changes, or a dev environment teammates can share. Here's the setup I actually use.
Why Three Environments Matter
The short version: production is for users, staging is for catching bugs before users see them, and dev is where you break things on purpose.
A lot of teams skip staging because it feels like extra work. They deploy directly to production and rely on rollbacks when things go wrong. That works until it doesn't — and when it doesn't, it's usually a Friday afternoon.
The Setup
On PandaStack, each environment is a separate project (container deployment) with its own environment variables. Your database is also separate per environment:
pandastack-myapp-dev → dev-db (PostgreSQL dev instance)
pandastack-myapp-staging → staging-db (PostgreSQL staging instance)
pandastack-myapp-prod → prod-db (PostgreSQL prod instance)Branch Strategy
The simplest approach maps Git branches to environments:
| Branch | Deploys to | Database |
|---|---|---|
main | Production | prod-db |
staging | Staging | staging-db |
develop | Dev | dev-db |
In PandaStack, each project can be configured to deploy from a specific branch. When you merge a PR into staging, it deploys to staging. When you merge into main, it goes to production. Automatic, no manual deploys needed.
Environment Variables Per Environment
Never share database URLs or API keys between environments. Keep them completely separate. In PandaStack's project settings, each project has its own set of env vars:
Dev:
DATABASE_URL=postgresql://...dev-db...
LOG_LEVEL=debug
EXTERNAL_API_URL=https://sandbox.external-api.comStaging:
DATABASE_URL=postgresql://...staging-db...
LOG_LEVEL=info
EXTERNAL_API_URL=https://sandbox.external-api.comProduction:
DATABASE_URL=postgresql://...prod-db...
LOG_LEVEL=warn
EXTERNAL_API_URL=https://api.external-api.comKeeping Staging Data Fresh
Staging is most useful when its data looks like production. Schedule a nightly dump-and-restore:
# PandaStack cronjob: runs at 2am UTC
pg_dump $PROD_DB | psql $STAGING_DBRun this as a PandaStack cronjob so it's automatic and logged.
Custom Domains
Typically:
- Production:
app.yourdomain.com(custom domain in PandaStack) - Staging:
staging.yourdomain.comor the default PandaStack subdomain - Dev: PandaStack default subdomain is fine
Don't bother with a custom domain for dev — the PandaStack subdomain is perfectly accessible for testing.
Pull Request Previews
For teams doing code review, you can spin up temporary environments per PR:
- 1Create a new PandaStack project via the CLI in your CI workflow
- 2Deploy the PR branch to it
- 3Comment the preview URL on the PR
- 4Tear it down after merge
# In your GitHub Actions workflow
panda project create --name "preview-pr-$PR_NUMBER" --branch "pr-$PR_NUMBER"
panda deploy --project "preview-pr-$PR_NUMBER"
echo "Preview: https://preview-pr-$PR_NUMBER.pandastack.io"Monitoring Across Environments
Set up separate alert rules for each environment. For staging, you might want all errors emailed. For production, you want Slack alerts for critical errors and daily summaries for everything else.
In PandaStack: Monitoring → Alerts → New Alert, select the project, and configure thresholds per environment.
The One Rule
Never manually deploy to production without going through staging first. Even small "one-line" changes bite you when they don't. The extra 15 minutes to merge into staging, verify it works, and then merge into main has saved me countless times.
Full docs: [docs.pandastack.io](https://docs.pandastack.io).