Back to Blog
Tutorial11 min read2026-07-04

How to Deploy Saleor E-commerce Platform

Saleor is a GraphQL-first, headless commerce platform built on Django. Here's how to self-host the Saleor core API with PostgreSQL, Redis, and a Celery worker on a modern cloud platform.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

Saleor is a serious, GraphQL-native e-commerce platform written in Python/Django. It powers real storefronts at scale, and because it's API-first you can put any frontend in front of it. The trade-off is that Saleor is *not* a single container — a production deployment is a small constellation of services. This guide explains what each piece does and how to run them.

Saleor's architecture

A minimal but production-shaped Saleor deployment includes:

ComponentRole
Saleor API (Django/ASGI)The GraphQL core, served via uvicorn/gunicorn
PostgreSQLPrimary datastore (Saleor recommends a recent major version)
RedisCelery broker + cache
Celery workerAsync tasks: emails, webhooks, exports
Object storage (S3)Product media and static files
Saleor DashboardOptional React admin UI (static site)

The important mental model: the API and the Celery worker run the *same codebase* but with different start commands, and they share the database and Redis.

Step 1: Prepare configuration

Saleor is configured almost entirely through environment variables. The critical ones:

DATABASE_URL=postgres://user:pass@host:5432/saleor
REDIS_URL=redis://host:6379/0
CELERY_BROKER_URL=redis://host:6379/1
SECRET_KEY=<long random string>
ALLOWED_HOSTS=api.yourstore.com
ALLOWED_CLIENT_HOSTS=yourstore.com
DEFAULT_FROM_EMAIL=noreply@yourstore.com
# S3-compatible media
AWS_STORAGE_BUCKET_NAME=saleor-media
AWS_MEDIA_BUCKET_NAME=saleor-media
AWS_S3_ENDPOINT_URL=https://...

Saleor ships an official Docker image, which makes deployment far more predictable than building from source.

Step 2: Run the database migrations and populate data

Saleor needs migrations applied and, on first boot, you typically want to populate the database. Run a one-off command:

python manage.py migrate
# optional: load demo data for a first look
python manage.py populatedb --createsuperuser

In a container platform, run this as a one-off job or as a release/pre-deploy command so it executes once per deploy rather than per replica.

Step 3: Deploy the API

Use Saleor's official image. The API runs as an ASGI app:

FROM ghcr.io/saleor/saleor:3.20
# the image already has a sane entrypoint

The start command for the web service:

gunicorn saleor.asgi:application -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000

On PandaStack, deploying any Dockerfile is first-class. Create a container app, point it at your repo (or the official image), and set the start command above. Bind to the injected PORT.

Step 4: Deploy the Celery worker

The worker is the same image with a different command — no GraphQL, just background processing:

celery -A saleor --app=saleor.celeryconf:app worker --loglevel=info

Create a second container app from the same image with this start command. It has no public HTTP endpoint — it just connects to Redis and Postgres. Both the API and worker must share the same DATABASE_URL, REDIS_URL, and SECRET_KEY.

Step 5: Wire up data services

This is where a platform with managed databases saves real time. On PandaStack:

  1. 1Provision a managed PostgreSQL instance. Saleor is happy on PostgreSQL 16.x.
  2. 2Provision a managed Redis instance (used for both cache and the Celery broker).
  3. 3Link both to the API app and worker app. The connection strings are injected as env vars.

For media, point Saleor at S3-compatible storage. A self-hosted MinIO bucket works perfectly via AWS_S3_ENDPOINT_URL.

Step 6: Deploy the Dashboard (optional)

The Saleor Dashboard is a static React app. Build it pointing at your API:

API_URL=https://api.yourstore.com/graphql/ npm run build

Deploy the build/ output as a static site. PandaStack auto-detects the framework and serves it with automatic SSL and a CDN. Static sites are unlimited on Pro and Premium plans.

Scaling and resource notes

  • The API is CPU-bound under GraphQL load; the worker is bursty. Scale them independently — that's the whole point of splitting them.
  • Saleor's GraphQL schema is large; give the API enough memory. Start on a small compute tier and watch metrics before sizing up.
  • Use database connection pooling. Many Django replicas times Saleor's connection count can exhaust Postgres max_connections.

Honest caveats

Saleor is a heavyweight platform. If you're building a tiny shop, it's overkill — something like Medusa or even a hosted SaaS may serve you better. Saleor shines when you need a robust GraphQL API, multi-channel commerce, and deep customization. Budget for the operational reality of running an API plus a worker plus two data stores.

Wrapping up

Saleor's deployment complexity is really just "one app, two roles, two data stores." Once you internalize that, it's straightforward: API container, worker container, managed Postgres, managed Redis, S3 media, static Dashboard.

PandaStack's managed PostgreSQL and Redis plus first-class Dockerfile support make this constellation easy to wire together — and the free tier is enough to stand up a dev instance. Try it at https://dashboard.pandastack.io.

References

  • Saleor documentation: https://docs.saleor.io/
  • Saleor deployment docs: https://docs.saleor.io/setup/deployment
  • Saleor Docker images: https://github.com/saleor/saleor/pkgs/container/saleor
  • Saleor Dashboard: https://github.com/saleor/saleor-dashboard
  • Celery documentation: https://docs.celeryq.dev/en/stable/

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also