Spree Commerce logo

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 screenshot

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.