Spree Commerce
Open-source headless ecommerce platform with a REST API and Next.js storefront
Alternative to: Shopify, Magento, WooCommerce, Salesforce Commerce Cloud
Spree Commerce is a complete open-source ecommerce platform for Ruby on Rails, offering a full REST API, TypeScript SDK, and a production-ready Next.js storefront out of the box. It covers catalog management, cart and checkout, multi-currency and multi-region pricing, promotions, and an admin panel, making it a self-hosted alternative to hosted platforms like Shopify or Magento.
Spree Commerce Docker Compose example
Self-host Spree Commerce on your own server, homelab, or VPS starting from this Docker Compose example.
It runs Spree Commerce in Docker containers using the official postgres:18-alpine, redis:7-alpine, getmeili/meilisearch:latest, axllent/mailpit:latest, ghcr.io/spree/spree:latest, ghcr.io/spree/spree:latest images, with persistent volumes and automatic restarts preconfigured.
Review the environment variables and adjust them to your setup, save the file as compose.yml (or docker-compose.yml), and start the stack with docker compose up -d.
services:
postgres:
image: postgres:18-alpine
environment:
# Passwordless auth on the internal compose network only — Postgres is never exposed outside it.
POSTGRES_HOST_AUTH_METHOD: "trust"
PGDATA: "/var/lib/postgresql/18/docker"
volumes:
- postgres_data:/var/lib/postgresql
healthcheck:
test: pg_isready -U postgres
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
healthcheck:
test: redis-cli ping
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
meilisearch:
image: getmeili/meilisearch:latest
volumes:
- meilisearch_data:/meili_data
healthcheck:
test: curl -f http://localhost:7700/health || exit 1
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
mailpit:
image: axllent/mailpit:latest
environment:
MP_MAX_MESSAGES: "500"
MP_SMTP_AUTH_ACCEPT_ANY: "true"
MP_SMTP_AUTH_ALLOW_INSECURE: "true"
restart: unless-stopped
web:
image: ghcr.io/spree/spree:latest
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
meilisearch:
condition: service_healthy
mailpit:
condition: service_started
environment:
# Internal Postgres connection (passwordless trust auth on the compose network).
DATABASE_URL: "postgres://postgres@postgres:5432/spree_production"
# Internal Redis connection used for caching and Sidekiq queues.
REDIS_URL: "redis://redis:6379/0"
# Rails secret used to sign cookies and sessions. Generate a long random value (e.g. `openssl rand -hex 64`).
SECRET_KEY_BASE: "changeme"
# Redirect all HTTP requests to HTTPS. Enable when TLS is terminated at Spree itself.
RAILS_FORCE_SSL: "false"
# Trust the X-Forwarded-Proto header so Rails treats requests as HTTPS. Set "true" behind a TLS-terminating reverse proxy.
RAILS_ASSUME_SSL: "false"
# Internal Meilisearch endpoint powering catalog search.
MEILISEARCH_URL: "http://meilisearch:7700"
# SMTP host for outgoing mail. Defaults to the bundled Mailpit catch-all; point at a real SMTP server for delivery.
SMTP_HOST: "mailpit"
# SMTP port. 1025 is the bundled Mailpit endpoint; use 587 for most real SMTP providers.
SMTP_PORT: "1025"
volumes:
- storage_data:/rails/storage
healthcheck:
test: curl -f http://localhost:3000/up || exit 1
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
restart: unless-stopped
worker:
image: ghcr.io/spree/spree:latest
command: bundle exec sidekiq
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
meilisearch:
condition: service_healthy
mailpit:
condition: service_started
environment:
# Internal Postgres connection (passwordless trust auth on the compose network).
DATABASE_URL: "postgres://postgres@postgres:5432/spree_production"
# Internal Redis connection used for caching and Sidekiq queues.
REDIS_URL: "redis://redis:6379/0"
# Rails secret used to sign cookies and sessions. Generate a long random value (e.g. `openssl rand -hex 64`).
SECRET_KEY_BASE: "changeme"
# Redirect all HTTP requests to HTTPS. Enable when TLS is terminated at Spree itself.
RAILS_FORCE_SSL: "false"
# Trust the X-Forwarded-Proto header so Rails treats requests as HTTPS. Set "true" behind a TLS-terminating reverse proxy.
RAILS_ASSUME_SSL: "false"
# Internal Meilisearch endpoint powering catalog search.
MEILISEARCH_URL: "http://meilisearch:7700"
# SMTP host for outgoing mail. Defaults to the bundled Mailpit catch-all; point at a real SMTP server for delivery.
SMTP_HOST: "mailpit"
# SMTP port. 1025 is the bundled Mailpit endpoint; use 587 for most real SMTP providers.
SMTP_PORT: "1025"
# Sidekiq worker thread count (also its Postgres pool size).
RAILS_MAX_THREADS: "27"
volumes:
- storage_data:/rails/storage
restart: unless-stopped
volumes:
postgres_data:
redis_data:
meilisearch_data:
storage_data:
Values set to changeme are required — replace them with your own
values before starting Spree Commerce.
Prefer a managed setup? WinterFlow installs, configures, and updates Spree Commerce for you using this same Docker Compose configuration.