Saleor E-Commerce Platform Development
Saleor — Python/Django e-commerce platform with GraphQL API as single interface. Stack: Django 4.x + Graphene-Django, PostgreSQL, Celery + Redis. Architecturally headless by default: backend provides GraphQL API, frontend separate (official starter — Next.js).
Architecture
┌──────────────────────┐
│ Saleor Core (Django) │
├──────┬───────────────┤
│GraphQL API │ Webhooks│
├──────┴───────────────┤
│ Channel System │
├──────┬────────┬──────┤
│Products│Checkout│Orders│
├──────┴────────┴──────┤
│PostgreSQL│Redis│Celery│
└──────────────────────┘
Key concept: Channel — each channel has own currency, countries, pricing. One product available in multiple channels with different prices.
Installation
git clone https://github.com/saleor/saleor.git
cd saleor
docker compose up -d
# Or manual
python -m venv venv
pip install -r requirements.txt
# .env file
SECRET_KEY=your-key
DATABASE_URL=postgresql://saleor:pass@localhost/saleor
CELERY_BROKER_URL=redis://localhost:6379/0
# Migrate
python manage.py migrate
python manage.py createsuperuser
GraphQL API
All frontend communication via GraphQL. Endpoint: /graphql/.
query ProductList($channel: String!, $first: Int!) {
products(channel: $channel, first: $first) {
edges {
node {
id name slug
pricing { priceRange { start { gross { amount currency } } } }
variants {
id sku quantityAvailable(countryCode: RU)
pricing { price { gross { amount } } }
}
}
}
}
}
Channels
mutation CreateChannel {
channelCreate(input: {
name: "Russia"
slug: "ru"
currencyCode: "RUB"
defaultCountry: RU
countries: [RU, BY, KZ]
}) {
channel { id slug name currencyCode }
}
}
Webhooks
Key events: ORDER_CREATED, ORDER_PAID, ORDER_FULFILLED, PRODUCT_UPDATED, PAYMENT_GATEWAY_INITIALIZE_SESSION.
mutation CreateWebhook {
webhookCreate(input: {
name: "CRM Sync"
targetUrl: "https://crm.example.com/orders"
events: [ORDER_CREATED, ORDER_PAID]
}) {
webhook { id name }
}
}
Custom Payment Provider
from django.http import JsonResponse
import hmac, hashlib
def saleor_webhook(request):
signature = request.headers.get('Saleor-Signature', '')
secret = b'webhook-secret'
computed = hmac.new(secret, request.body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, computed):
return JsonResponse({'error': 'Invalid'}, status=400)
event_type = request.headers.get('Saleor-Event')
payload = json.loads(request.body)
if event_type == 'ORDER_PAID':
sync_order_to_crm.delay(payload['order']['id'])
return JsonResponse({'status': 'ok'})
Performance Settings
GRAPHQL_QUERY_MAX_COMPLEXITY = 50000
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": os.environ.get("REDIS_URL"),
}
}
Timeline
- Basic setup + Dashboard + Next.js Starter: 2–3 weeks
- Full store 2–3 markets, custom product types, channels: 5–8 weeks
- Enterprise multi-channel with custom Apps: 14–20 weeks







