docker.recipes

Medusa + PostgreSQL + Redis + MinIO

advanced

Headless commerce platform with full backend services.

Overview

Medusa is a modern headless commerce platform built with Node.js that provides a flexible, API-first approach to e-commerce. Unlike monolithic platforms like Shopify or WooCommerce, Medusa separates the backend commerce logic from the frontend presentation layer, enabling developers to build custom storefronts using any technology stack. The platform handles core commerce operations including product catalog management, order processing, customer management, and payment integration through a comprehensive REST API. This stack combines Medusa's commerce engine with PostgreSQL for transactional data storage, Redis for session management and caching, and MinIO for S3-compatible object storage of product images and digital assets. The architecture provides enterprise-grade data persistence through PostgreSQL's ACID compliance, sub-millisecond response times via Redis caching, and scalable media storage through MinIO's high-performance object store. This configuration creates a complete headless commerce backend that can power multiple storefronts, mobile applications, or integrate with existing business systems. The combination is ideal for businesses requiring custom e-commerce experiences, multi-channel selling, or complex B2B commerce workflows. Companies choose this stack when they need the flexibility of headless architecture without vendor lock-in, full control over their commerce data, and the ability to scale each component independently based on traffic patterns.

Key Features

  • Headless commerce API supporting product catalogs, orders, customers, and multi-region selling
  • PostgreSQL JSONB storage for flexible product attributes and complex catalog structures
  • Redis-powered session management and cart persistence for high-performance checkout flows
  • MinIO S3-compatible storage for product images, digital downloads, and media assets
  • Built-in admin dashboard for managing products, orders, and customer data
  • Multi-currency and multi-region support with tax and shipping calculations
  • Pluggable payment processor integration supporting Stripe, PayPal, and custom gateways
  • Event-driven architecture with Redis pub/sub for real-time inventory and order updates

Common Use Cases

  • 1Headless e-commerce for React, Vue, or mobile app storefronts
  • 2Multi-brand retailers managing separate storefronts from unified inventory
  • 3B2B marketplaces requiring custom pricing and approval workflows
  • 4Digital product stores selling downloads, subscriptions, or SaaS offerings
  • 5International commerce with multi-currency and region-specific catalogs
  • 6Marketplace platforms connecting multiple vendors with centralized order management
  • 7Custom commerce integrations for existing business applications or ERPs

Prerequisites

  • Minimum 4GB RAM for full stack operation (1GB PostgreSQL, 512MB Redis, 2GB MinIO, 512MB Medusa)
  • Docker Engine 20.10+ and Docker Compose 2.0+ for container orchestration
  • Ports 7001, 9000, and 9001 available for admin interface, API, and MinIO console
  • Basic understanding of REST APIs and headless architecture concepts
  • Node.js knowledge for customizing Medusa plugins and business logic
  • PostgreSQL familiarity for database maintenance and backup procedures

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 medusa:
3 image: medusajs/medusa:latest
4 environment:
5 - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/medusa
6 - REDIS_URL=redis://redis:6379
7 - NODE_ENV=production
8 - JWT_SECRET=${JWT_SECRET}
9 - COOKIE_SECRET=${COOKIE_SECRET}
10 - STORE_CORS=http://localhost:8000
11 - ADMIN_CORS=http://localhost:7001
12 - MINIO_ENDPOINT=minio
13 - MINIO_PORT=9000
14 - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
15 - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
16 - MINIO_BUCKET=medusa
17 ports:
18 - "9000:9000"
19 depends_on:
20 - postgres
21 - redis
22 - minio
23 networks:
24 - medusa-network
25 restart: unless-stopped
26
27 postgres:
28 image: postgres:15
29 environment:
30 - POSTGRES_USER=${POSTGRES_USER}
31 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
32 - POSTGRES_DB=medusa
33 volumes:
34 - postgres-data:/var/lib/postgresql/data
35 networks:
36 - medusa-network
37 restart: unless-stopped
38
39 redis:
40 image: redis:alpine
41 volumes:
42 - redis-data:/data
43 networks:
44 - medusa-network
45 restart: unless-stopped
46
47 minio:
48 image: minio/minio:latest
49 command: server /data --console-address ":9001"
50 environment:
51 - MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
52 - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
53 volumes:
54 - minio-data:/data
55 ports:
56 - "9001:9001"
57 networks:
58 - medusa-network
59 restart: unless-stopped
60
61 admin:
62 image: medusajs/admin:latest
63 environment:
64 - MEDUSA_BACKEND_URL=http://localhost:9000
65 ports:
66 - "7001:7001"
67 depends_on:
68 - medusa
69 networks:
70 - medusa-network
71 restart: unless-stopped
72
73volumes:
74 postgres-data:
75 redis-data:
76 minio-data:
77
78networks:
79 medusa-network:
80 driver: bridge

.env Template

.env
1# Medusa
2POSTGRES_USER=medusa
3POSTGRES_PASSWORD=secure_postgres_password
4JWT_SECRET=your-super-secret-jwt-key
5COOKIE_SECRET=your-super-secret-cookie-key
6
7# MinIO
8MINIO_ACCESS_KEY=minioadmin
9MINIO_SECRET_KEY=secure_minio_password

Usage Notes

  1. 1API at http://localhost:9000
  2. 2Admin at http://localhost:7001
  3. 3MinIO console at http://localhost:9001
  4. 4Seed store: medusa seed -f data/seed.json
  5. 5Create admin: medusa user -e admin@example.com -p password

Individual Services(5 services)

Copy individual services to mix and match with your existing compose files.

medusa
medusa:
  image: medusajs/medusa:latest
  environment:
    - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/medusa
    - REDIS_URL=redis://redis:6379
    - NODE_ENV=production
    - JWT_SECRET=${JWT_SECRET}
    - COOKIE_SECRET=${COOKIE_SECRET}
    - STORE_CORS=http://localhost:8000
    - ADMIN_CORS=http://localhost:7001
    - MINIO_ENDPOINT=minio
    - MINIO_PORT=9000
    - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
    - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
    - MINIO_BUCKET=medusa
  ports:
    - "9000:9000"
  depends_on:
    - postgres
    - redis
    - minio
  networks:
    - medusa-network
  restart: unless-stopped
postgres
postgres:
  image: postgres:15
  environment:
    - POSTGRES_USER=${POSTGRES_USER}
    - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
    - POSTGRES_DB=medusa
  volumes:
    - postgres-data:/var/lib/postgresql/data
  networks:
    - medusa-network
  restart: unless-stopped
redis
redis:
  image: redis:alpine
  volumes:
    - redis-data:/data
  networks:
    - medusa-network
  restart: unless-stopped
minio
minio:
  image: minio/minio:latest
  command: server /data --console-address ":9001"
  environment:
    - MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
    - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
  volumes:
    - minio-data:/data
  ports:
    - "9001:9001"
  networks:
    - medusa-network
  restart: unless-stopped
admin
admin:
  image: medusajs/admin:latest
  environment:
    - MEDUSA_BACKEND_URL=http://localhost:9000
  ports:
    - "7001:7001"
  depends_on:
    - medusa
  networks:
    - medusa-network
  restart: unless-stopped

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 medusa:
5 image: medusajs/medusa:latest
6 environment:
7 - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/medusa
8 - REDIS_URL=redis://redis:6379
9 - NODE_ENV=production
10 - JWT_SECRET=${JWT_SECRET}
11 - COOKIE_SECRET=${COOKIE_SECRET}
12 - STORE_CORS=http://localhost:8000
13 - ADMIN_CORS=http://localhost:7001
14 - MINIO_ENDPOINT=minio
15 - MINIO_PORT=9000
16 - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
17 - MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
18 - MINIO_BUCKET=medusa
19 ports:
20 - "9000:9000"
21 depends_on:
22 - postgres
23 - redis
24 - minio
25 networks:
26 - medusa-network
27 restart: unless-stopped
28
29 postgres:
30 image: postgres:15
31 environment:
32 - POSTGRES_USER=${POSTGRES_USER}
33 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
34 - POSTGRES_DB=medusa
35 volumes:
36 - postgres-data:/var/lib/postgresql/data
37 networks:
38 - medusa-network
39 restart: unless-stopped
40
41 redis:
42 image: redis:alpine
43 volumes:
44 - redis-data:/data
45 networks:
46 - medusa-network
47 restart: unless-stopped
48
49 minio:
50 image: minio/minio:latest
51 command: server /data --console-address ":9001"
52 environment:
53 - MINIO_ROOT_USER=${MINIO_ACCESS_KEY}
54 - MINIO_ROOT_PASSWORD=${MINIO_SECRET_KEY}
55 volumes:
56 - minio-data:/data
57 ports:
58 - "9001:9001"
59 networks:
60 - medusa-network
61 restart: unless-stopped
62
63 admin:
64 image: medusajs/admin:latest
65 environment:
66 - MEDUSA_BACKEND_URL=http://localhost:9000
67 ports:
68 - "7001:7001"
69 depends_on:
70 - medusa
71 networks:
72 - medusa-network
73 restart: unless-stopped
74
75volumes:
76 postgres-data:
77 redis-data:
78 minio-data:
79
80networks:
81 medusa-network:
82 driver: bridge
83EOF
84
85# 2. Create the .env file
86cat > .env << 'EOF'
87# Medusa
88POSTGRES_USER=medusa
89POSTGRES_PASSWORD=secure_postgres_password
90JWT_SECRET=your-super-secret-jwt-key
91COOKIE_SECRET=your-super-secret-cookie-key
92
93# MinIO
94MINIO_ACCESS_KEY=minioadmin
95MINIO_SECRET_KEY=secure_minio_password
96EOF
97
98# 3. Start the services
99docker compose up -d
100
101# 4. View logs
102docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/medusa-complete/run | bash

Troubleshooting

  • Medusa fails to connect to PostgreSQL: Verify POSTGRES_USER and POSTGRES_PASSWORD match in both services, ensure postgres container starts before medusa
  • Redis connection timeout errors: Check Redis container health with docker logs redis, verify redis:6379 hostname resolves within medusa-network
  • MinIO bucket access denied: Confirm MINIO_ACCESS_KEY and MINIO_SECRET_KEY are set correctly, create medusa bucket manually via MinIO console at localhost:9001
  • Admin dashboard shows 'Backend unreachable': Ensure medusa container is running and MEDUSA_BACKEND_URL points to http://localhost:9000, check CORS settings
  • Database migration failures on startup: Run docker exec -it medusa-container medusa migrations run, check PostgreSQL logs for permission or disk space issues
  • High memory usage by PostgreSQL: Tune shared_buffers and work_mem in PostgreSQL config, consider adding postgresql.conf volume mount for custom settings

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space