Deploy to production
Production deployments should build the app, apply committed migrations, then run the web server and at least one worker.
pnpm run buildThe build creates:
Directorydist/
Directoryui/
- …
Directoryopenshop/
Directoryserver/
- …
Configure environment
Section titled “Configure environment”Single-app deployments usually need:
DATABASE_URL=postgresql://...SHOPIFY_API_KEY=...SHOPIFY_API_SECRET=...HOST=https://your-app.example.comENCRYPTION_KEY=<64 hex characters>Generate an encryption key:
openssl rand -hex 32ENCRYPTION_KEY protects provider credentials and Shopify access tokens. Treat it as required in production.
Apply migrations
Section titled “Apply migrations”Generate and review migrations in development or CI:
pnpm exec openshop migrate generatepnpm exec openshop migrate checkCommit the generated SQL in ./drizzle, then apply committed migrations before starting production processes:
pnpm exec openshop migrateopenshop migrate only applies SQL from ./drizzle. It does not run generation tooling.
Start processes
Section titled “Start processes”Configure two independently supervised services from the same build:
| Service | Command | Replicas |
|---|---|---|
| Web | pnpm exec openshop start |
One or more behind your router |
| Worker | pnpm exec openshop worker --concurrency=5 |
One or more |
Do not place the commands one after the other in a deploy script. Both are long-running processes, so openshop start would prevent the shell from ever starting the worker. Use separate platform process types, containers, system services, or the template’s ecosystem.config.cjs.
openshop start serves HTTP traffic and dispatches cron runs. It does not execute queued flow runs. At least one worker must be running for queued runs to complete.
Each web replica starts a scheduler. OpenShop does not currently elect one
scheduler leader, so prefer one web replica when using crons, or accept and
handle duplicate dispatch attempts. Flow concurrency can reject overlapping
runs, but it is not a cron de-duplication guarantee.
Every web and worker replica needs the same DATABASE_URL, Shopify configuration, and ENCRYPTION_KEY. Each process creates its own PostgreSQL pool; tune PGPOOL_MAX with the total replica count and database connection limit in mind.
Verify it worked
Section titled “Verify it worked”- The web process starts without migration errors.
- The worker process starts and reports no database connectivity errors.
- The embedded admin UI loads inside Shopify.
- A test flow run moves from queued to completed or failed with logs.
Rollback notes
Section titled “Rollback notes”OpenShop does not apply migrations on boot. If a deploy fails before migrations are applied, roll back the app process only. If committed SQL was already applied, use your normal database rollback or forward-fix process.