Appearance
Staging / Preview Environment
This guide explains how to spin up an isolated staging stack for the Bulk Product Editor app. The staging stack mirrors production while keeping data and Shopify credentials separate so that QA and reviewers can test safely.
Current Setup
| Environment | Render Service | Neon Branch | Endpoint |
|---|---|---|---|
| Production | BPE | main (br-frosty-dew-aedj6zx6) | ep-billowing-sound-aej92wq7 |
| Staging | BPE-staging | staging (br-bitter-glitter-aetxngom) | ep-bold-moon-ae7orloc |
| Preview | BPE-preview | preview (br-quiet-bush-ae493ep6) | ep-nameless-butterfly-ae96woar |
1. Database (Neon)
- List projects and identify the production project ID:bash
neon projects list - Create a dedicated branch inside the existing project (keeps networking rules and roles intact):bash
neon branches create \ --project-id blue-breeze-89779170 \ --name staging \ --from br-frosty-dew-aedj6zx6 - Capture connection strings for the new branch:bash
# Direct connection (for migrations) neon connection-string staging \ --project-id blue-breeze-89779170 \ --role-name neondb_owner # Pooled connection (for app runtime) neon connection-string staging \ --project-id blue-breeze-89779170 \ --role-name neondb_owner \ --pooled - Set these in Render:
DATABASE_URL: pooled connection string (with-poolerin hostname)DIRECT_URL: direct connection string (without-pooler)
2. Shopify staging app
Create a distinct public app in the Partner Dashboard (copy the scopes and webhooks from production), then note:
- API key → set as
SHOPIFY_API_KEYin Render - API secret → set as
SHOPIFY_API_SECRETin Render - App URL →
https://bpe-staging.onrender.com(set asSHOPIFY_APP_URL) - Redirect URL →
https://bpe-staging.onrender.com/auth/callback - Admin API version → defaults to stable (
SHOPIFY_API_VERSION=2025-07)
Create or reuse a development store dedicated to staging installs and install the new app there.
3. Render service
Provision a new web service in the Render dashboard. Current staging service: BPE-staging (srv-d4etgt2dbo4c73do0s9g).
Configuration:
- Runtime: Docker, using the same repo and Dockerfile as production
- Branch:
main(auto-deploy enabled) - Region:
ohio - Plan:
freeorstarter - Health check path:
/health
Required environment variables:
| Variable | Value |
|---|---|
DATABASE_URL | Staging Neon pooled connection |
DIRECT_URL | Staging Neon direct connection |
SHOPIFY_API_KEY | Staging app API key |
SHOPIFY_API_SECRET | Staging app API secret |
SHOPIFY_APP_URL | https://bpe-staging.onrender.com |
NODE_ENV | production |
JOB_QUEUE_ENABLED | 1 |
SCOPES | read_products,write_products |
4. CI (optional)
You can keep your existing CI (.github/workflows/ci.yml) to run tests on pushes/PRs. A staging-specific workflow is not required:
- Render will auto-deploy the
stagingbranch. - Migrations run on container startup via
npm run docker-start, which callsscripts/prisma-setup.shand usesDIRECT_URL(orDATABASE_URL) from the Render service.
5. Local development with staging env
When working on the staging branch locally:
Create a
.env.stagingfile (gitignored) with the staging credentials:bash# Staging environment configuration APP_ENV=staging NODE_ENV=production SHOPIFY_API_KEY=<staging_api_key> SHOPIFY_API_SECRET=<staging_api_secret> SHOPIFY_APP_URL=https://bpe-staging.onrender.com SCOPES=read_products,write_products # Staging Neon branch connection strings DATABASE_URL='postgresql://...<staging-pooler>...neon.tech/neondb?sslmode=require' DIRECT_URL='postgresql://...<staging-direct>...neon.tech/neondb?sslmode=require' PRISMA_MIGRATE_ADVISORY_LOCK_TIMEOUT=60000 TEST_MODE=0 JOB_QUEUE_ENABLED=1 MAX_CONCURRENT_SHOPS=5npm run devinvokesscripts/dev.sh, which:- Always loads
.envfirst (base config) - Loads
.env.localif present (per-developer overrides) - Loads
.env.stagingonly when git branch isstaging
- Always loads
6. Housekeeping
- Periodically reset or reseed the preview database if it drifts too far from production.
- Rotate Shopify API secrets and update GitHub/Render secrets accordingly.
- Document who owns the preview environment and when it can be torn down.