Loading...
Loading...
Use when deploying a Spree 6 application to production or scaling it — Docker image builds, Render/AWS/Railway/Kubernetes/VPS, required environment variables, Solid Queue (jobs in Puma vs a dedicated `bin/jobs` worker), Solid Cache, optional Sidekiq/Redis, the Mission Control `/jobs` dashboard, serving the React dashboard at `/dashboard` or from a static host, migrations on boot and `spree:upgrade`, S3/R2 storage, CDN_HOST, Meilisearch, PostgreSQL/MySQL/SQLite, and observability (spree_opentelemetry, Sentry). Common phrasings include "deploy Spree", "Spree Docker image", "spree build --production", "Render deploy", "Spree environment variables", "split the worker", "SOLID_QUEUE_IN_PUMA", "jobs not running", "/jobs dashboard locked", "dashboard 404 in production", "images point at localhost", "S3 setup", "Sidekiq instead of Solid Queue", "OpenTelemetry tracing". Spree-specific bits only — generic Rails deployment is out of scope.
npx skill4agent add spree/agent-skills spree-deployment/dashboardserver/backend/apps/dashboard/| Shape | When | How |
|---|---|---|
| Combined (default) | Most stores; one container is the whole app | Web container runs Puma with the Solid Queue plugin ( |
| Split worker | Heavy imports, big catalogs, marketplaces syncing many sellers, multi-tenant | Same image, second service with command |
| Distributed | Independent scaling/release of surfaces | API behind a load balancer; dashboard as static files on a CDN; storefront (Next.js) on Vercel/Node host |
| Sidekiq | Only when a dedicated Solid Queue worker with raised | Swap Active Job adapter to Sidekiq on Redis/Valkey (see below) |
spree eject # once — materializes server/ incl. its production Dockerfile
spree build --production # → <project>-spree:latest
spree build --production --tag registry.example.com/my-store:v42
# without the CLI, from the project root:
docker build . -f server/Dockerfile -t my-storeserver/apps/dashboard/apps/dashboard/spree build --production.spree-custom-app.spree-custom-dashboardserver/server/Dockerfileghcr.io/spree/spree:<version>DATABASE_URLSECRET_KEY_BASERAILS_HOST| Variable | Why it matters |
|---|---|
| |
| |
| Encrypt webhook signing secrets, gateway customer IDs and OAuth identity tokens at rest. Unset → plaintext + a boot warning. Generate with |
| Public host (no protocol) for email links, webhook payloads, and attachment URLs in API responses. Unset → URLs point at |
| Optional separate host for assets and images (sets |
| |
| Worker threads (default 3) / worker processes (default 1) |
| Cap on concurrent CSV import group jobs (default 75% of |
| HTTP Basic auth for |
| Without |
| Object storage for uploads — required on ephemeral filesystems |
| Both default |
| Optional integrations (below) |
PORTRAILS_MAX_THREADSWEB_CONCURRENCYautodatabase.ymlRAILS_MAX_THREADS + JOB_THREADS + 3database.ymlbin/docker-entrypointbin/rails db:preparebin/jobsbin/rails db:preparebin/rails db:migratebin/rails spree:upgradeDRY_RUN=1spree-upgradebin/rails spree:setup:tokenconfig/puma.rbplugin :solid_queueSOLID_QUEUE_IN_PUMAtrueconfig/queue.yml"*"Spree.queues.<name>:defaultconfig/initializers/spree.rbspree_*spree-performanceconfig/recurring.ymlSpree::StockReservations::ExpireJobSpree::Orders::FinalizeStaleDraftsJobSpree::Carts::ReapExpiredJobSpree::Collections::RegenerateTimeBasedJobspree:price_history:prunecommand:Spree::SellerPayouts::SweepDueJobSpree::SellerTransfers::ExecutePendingDueJobconfig/recurring.ymlbin/jobsDATABASE_URLSECRET_KEY_BASERAILS_HOSTJOB_THREADSJOB_CONCURRENCYSOLID_QUEUE_IN_PUMA=falseSPREE_IMPORT_JOB_CONCURRENCY/jobs/jobsMISSION_CONTROL_USERMISSION_CONTROL_PASSWORDspreespree123# Gemfile
gem "sidekiq"
gem "sidekiq-cron" # replaces config/recurring.yml
# config/application.rb
config.active_job.queue_adapter = :sidekiqconfig/sidekiq.ymlSpree.queuesdefaultmailersactive_storage_*"*"recurring.ymlconfig/schedule.ymlspree:price_history:pruneRails.application.load_tasksRake::Task[...].tap(&:reenable).invokeSidekiq::Webbundle exec sidekiqRAILS_MAX_THREADS >= SIDEKIQ_CONCURRENCYSOLID_QUEUE_IN_PUMAconfig.cache_store = :solid_cache_storeredisconfig.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"] }config/environments/production.rbspree_dashboard/dashboard/sellersSpree::Dashboard.dist_pathSPREE_DASHBOARD_DIST_PATHSPREE_SELLER_PANEL_DIST_PATHcd apps/dashboard && VITE_SPREE_API_URL=https://api.example.com pnpm builddist//* → /index.htmlSameSite=None; SecureVITE_*spree_dashboardAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_REGIONAWS_BUCKETCLOUDFLARE_ENDPOINTCLOUDFLARE_ACCESS_KEY_IDCLOUDFLARE_SECRET_ACCESS_KEYCLOUDFLARE_BUCKETconfig/storage.yml/rails/active_storage/representations//assetsCDN_HOSTSpree::SearchProvider::Database# Gemfile
gem "spree_meilisearch"
# config/initializers/spree.rb
Spree.search_provider = 'SpreeMeilisearch::SearchProvider'MEILISEARCH_URLhttp://localhost:7700MEILISEARCH_API_KEYbin/rails spree:search:reindexspree task search:reindexSENTRY_DSNsentry-railsgem 'spree_opentelemetry'OTEL_SERVICE_NAMEOTEL_EXPORTER_OTLP_ENDPOINTOTEL_EXPORTER_OTLP_TRACES_ENDPOINTOTEL_TRACES_SAMPLER=parentbased_traceidratioOTEL_TRACES_SAMPLER_ARGOTEL_SDK_DISABLED=trueSpree::Workflowtraces_sample_ratesentry-opentelemetrySpreeOpenTelemetry.install!Sentry.initOTEL_TRACES_EXPORTER=none/upcreate-spree-apprender.yamldockerfilePath./server/DockerfiledockerContextSECRET_KEY_BASEACTIVE_RECORD_ENCRYPTION_*MISSION_CONTROL_PASSWORDjobsbin/jobsbin/jobsSECRET_KEY_BASEDATABASE_URL/updb:migratedocker composewebpostgres| Symptom | Cause / fix |
|---|---|
Image/attachment URLs point at | |
| |
| Static-host dashboard can't log in / CORS errors | Origin not in Settings → Allowed Origins, or not HTTPS on both sides |
| |
| Jobs never run after splitting | Worker not running |
| Jobs run on Solid Queue but not on Sidekiq | Queue missing from |
| Pool smaller than |
| Uploads vanish after redeploy | Local disk storage on an ephemeral filesystem |
| No emails in production | |
| Search returns nothing on Meilisearch | Index never built — run |
| Checkout stock held forever / sellers never paid | |
| Store data looks half-migrated after a gem bump | |
Boot log: | |
| Webhook secrets / gateway customers unreadable after a deploy | Encryption keys changed or missing on this environment, or encryption enabled without first encrypting existing rows (see |
node_modules/@spree/docs/dist/developer/deployment/quickstart.mddocker.mdenvironment_variables.mdbackground_jobs.mdcaching.mddatabase.mdassets.mdcdn.mdemails.mdrender.mdaws.mdaws_ecs.mdnode_modules/@spree/docs/dist/developer/dashboard/deployment.mdnode_modules/@spree/docs/dist/developer/providers/observability.mdspree-performancespree-upgradespree-securityspree-multi-tenant