saleor/saleor

Saleor Core: the high performance, composable, headless commerce API.

22,819 stars Python 8 components

12 hidden assumptions · 6-stage pipeline · 8 components

Like any codebase, this backend api makes assumptions it never checks — most are routine. The ones worth your attention are below.

Processes GraphQL commerce API requests through Django web server

Requests enter through the GraphQL endpoint where they are authenticated via app tokens loaded by AppByTokenLoader with database caching. The GraphQL schema routes operations to domain-specific resolvers which use DataLoaders to efficiently fetch data from PostgreSQL. Business operations trigger webhook events that are dispatched asynchronously to registered app endpoints. Apps are installed by fetching and validating manifests, creating database records, and generating authentication tokens.

Under the hood, the system uses 3 feedback loops, 4 data pools, 4 control points to manage its runtime behavior.

A 8-component backend api. 4248 files analyzed. Data flows through 6 distinct pipeline stages.

Hidden Assumptions

Most of what this code assumes is routine. These 3 are the ones most likely to cause trouble here. The rest are minor; they're under "Show everything".

Worth your attention first

If an app token is revoked or an app is deactivated after being cached, the system continues serving the cached app_id for up to 30 days, granting access to unauthorized apps

Worth your attention first

Tokens could be matched to wrong apps during authentication, leading to permission escalation or wrong app context in requests

Worth your attention first

App installation fails silently or times out if the manifest server is temporarily unavailable, DNS fails, or network partitions occur during installation

Show everything (9 more)
Domain

Semantic version parsing for requiredSaleorVersion assumes standard NPM version format, but the custom RequiredSaleorVersionSpec.Parser changes prerelease policy from 'same-patch' to 'natural' without validating this change is safe

If this fails: Version compatibility checks may incorrectly allow incompatible app versions to install, leading to runtime errors when apps use unsupported API features

saleor/app/manifest_validations.py:clean_manifest_data
Scale

30-day cache timeout is appropriate for all deployment scenarios, regardless of security requirements, token rotation policies, or app lifecycle management needs

If this fails: In high-security environments requiring frequent token rotation, cached tokens remain valid far longer than intended, and in high-churn environments, cache may accumulate stale entries consuming memory

saleor/graphql/app/dataloaders/app.py:CACHE_TIMEOUT
Contract

The last_4s_to_raw_token_map structure correctly groups tokens by their last 4 characters, but tokens with identical last 4 chars could lead to incorrect cache invalidation of valid tokens

If this fails: Valid app tokens may be incorrectly removed from cache when other tokens sharing the same last 4 characters are invalidated, causing unnecessary database hits and authentication delays

saleor/graphql/app/dataloaders/app.py:AppByTokenLoader.remove_not_valid_tokens_from_cache
Resource

10MB icon file size limit is enforced consistently across all storage backends and network transfer scenarios, but no validation is shown for actual downloaded icon size before processing

If this fails: Apps could submit manifests with icons exceeding the limit, consuming excessive bandwidth and storage during download, or worse, causing memory exhaustion during image processing

saleor/app/installation_utils.py:MAX_ICON_FILE_SIZE
Contract

The database_connection_name parameter defaults to main database, but checkout operations assume this connection has write permissions and consistent read-after-write semantics

If this fails: If read replicas are configured as the default connection, checkout operations may fail with permission errors or encounter stale data after writes, corrupting order creation workflow

saleor/checkout/fetch.py:CheckoutLineInfo
Domain

App permissions are validated against the Permission model's current state, but no check ensures that permission assignments remain valid when permission definitions change in Saleor updates

If this fails: Apps may retain permissions that no longer exist or have changed meaning after Saleor upgrades, potentially granting unintended access or breaking app functionality

saleor/app/models.py:App
Temporal

MD5 hash provides sufficient uniqueness for cache keys across all possible tokens, but hash collisions could occur with large numbers of tokens over time

If this fails: Hash collisions would cause different tokens to share the same cache entry, leading to apps being authenticated with wrong credentials and potential data leakage between apps

saleor/graphql/app/dataloaders/app.py:create_app_cache_key_from_token
Environment

The __version__ import provides the current Saleor version in a format compatible with semantic version parsing, but version string format changes could break compatibility checks

If this fails: If Saleor version format changes (adding build metadata, changing prerelease format), app compatibility validation may fail incorrectly, blocking valid app installations

saleor/app/manifest_validations.py:RequiredSaleorVersionSpec
Resource

DataLoader cache is cleared after each GraphQL request completes, but no explicit memory cleanup is shown for large result sets or long-running requests

If this fails: Memory usage could grow unbounded during complex GraphQL queries that load large datasets, especially if requests are long-running or if cache cleanup fails

saleor/graphql/core/dataloaders:DataLoader

Open the standalone hidden-assumptions report for saleor →

How Data Flows Through the System

Requests enter through the GraphQL endpoint where they are authenticated via app tokens loaded by AppByTokenLoader with database caching. The GraphQL schema routes operations to domain-specific resolvers which use DataLoaders to efficiently fetch data from PostgreSQL. Business operations trigger webhook events that are dispatched asynchronously to registered app endpoints. Apps are installed by fetching and validating manifests, creating database records, and generating authentication tokens.

  1. Authenticate Request — AppByTokenLoader receives raw token from request headers, checks cache for valid app mapping, validates token hash against database, returns authenticated App instance [TokenInfo → App]
  2. Route GraphQL Operation — GraphQL schema parses query/mutation, validates against schema definition, routes to appropriate resolver in domain modules like product, order, checkout
  3. Load Data with Batching — DataLoader instances batch database queries during resolver execution, checking cache first then executing batched SQL queries to prevent N+1 problems
  4. Execute Business Logic — Domain resolvers execute business rules, call PluginsManager hooks for taxes/payments/validation, modify database state, prepare response data
  5. Dispatch Webhook Events — Business operations trigger webhook events that are queued and dispatched asynchronously to registered app endpoints with payload signing and retry logic
  6. Install New Apps — install_app fetches manifest from URL, validates with clean_manifest_data against ManifestSchema, creates App/AppToken/Webhook database records, activates app [ManifestSchema → App]

Data Models

The data structures that flow between stages — the contracts that hold the system together.

App saleor/app/models.py
Django model with id: UUID, name: str, identifier: str, permissions: ManyToMany[Permission], is_active: bool, manifest_url: str, webhooks: RelatedManager[Webhook]
Created during app installation from manifest, authenticated via tokens, permissions checked on each request, deactivated on removal
TokenInfo saleor/graphql/app/dataloaders/app.py
dataclass with raw_token: str, _cache_key: str | None, last_4 property, cache_key property
Created from incoming request tokens, used to lookup apps with cache optimization, validated against hashed database tokens
CheckoutLineInfo saleor/checkout/fetch.py
dataclass with lines: list[CheckoutLineInfo], database_connection_name: str defaulting to main database
Assembled during checkout operations, carries line item data through validation and conversion to orders
TaxLineData saleor/core/taxes.py
dataclass with tax_rate: Decimal, total_gross_amount: Decimal, total_net_amount: Decimal
Computed by tax plugins during checkout/order processing, includes per-line and shipping tax data
TransactionItem saleor/payment/interface.py
Django model representing payment transactions with action_type: str, amount: Decimal, currency: str, gateway response data
Created when payment actions occur, updated through gateway webhooks, linked to orders for financial tracking
ManifestSchema saleor/app/manifest_schema.py
Pydantic model with camelCase fields for app installation: name, version, permissions, webhooks, extensions, brand info
Parsed from remote manifest URLs during app installation, validated against schema, converted to App model instances

System Behavior

How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.

Data Pools

PostgreSQL Database (database)
Primary data store for all commerce entities, app registrations, permissions, and transactional state
DataLoader Cache (cache)
In-memory cache of batched database query results during single GraphQL request lifecycle
App Token Cache (cache)
Redis/memory cache of validated app tokens to avoid repeated hash validation
Webhook Queue (queue)
Celery task queue for asynchronous webhook delivery with retry logic

Feedback Loops

Delays

Control Points

Technology Stack

Django (framework)
Provides web framework, ORM, and admin interface for the commerce platform
GraphQL (library)
Single API endpoint for all commerce operations with type-safe schema and batched queries
PostgreSQL (database)
Primary database storing all commerce data, app configurations, and transactional state
Celery (runtime)
Asynchronous task queue for webhook delivery and background processing
Pydantic (library)
Validates app manifests and API schemas during installation and request processing
Redis/Cache (database)
Caches app authentication tokens and DataLoader query results

Key Components

Explore the interactive analysis

See the full architecture map, data flow, and code patterns visualization.

Analyze on CodeSea

Related Backend Api Repositories

Frequently Asked Questions

What is saleor used for?

Processes GraphQL commerce API requests through Django web server saleor/saleor is a 8-component backend api written in Python. Data flows through 6 distinct pipeline stages. The codebase contains 4248 files.

How is saleor architected?

saleor is organized into 4 architecture layers: GraphQL API Layer, Business Domain Modules, App & Extension System, Core Infrastructure. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.

How does data flow through saleor?

Data moves through 6 stages: Authenticate Request → Route GraphQL Operation → Load Data with Batching → Execute Business Logic → Dispatch Webhook Events → .... Requests enter through the GraphQL endpoint where they are authenticated via app tokens loaded by AppByTokenLoader with database caching. The GraphQL schema routes operations to domain-specific resolvers which use DataLoaders to efficiently fetch data from PostgreSQL. Business operations trigger webhook events that are dispatched asynchronously to registered app endpoints. Apps are installed by fetching and validating manifests, creating database records, and generating authentication tokens. This pipeline design reflects a complex multi-stage processing system.

What technologies does saleor use?

The core stack includes Django (Provides web framework, ORM, and admin interface for the commerce platform), GraphQL (Single API endpoint for all commerce operations with type-safe schema and batched queries), PostgreSQL (Primary database storing all commerce data, app configurations, and transactional state), Celery (Asynchronous task queue for webhook delivery and background processing), Pydantic (Validates app manifests and API schemas during installation and request processing), Redis/Cache (Caches app authentication tokens and DataLoader query results). A focused set of dependencies that keeps the build manageable.

What system dynamics does saleor have?

saleor exhibits 4 data pools (PostgreSQL Database, DataLoader Cache), 3 feedback loops, 4 control points, 3 delays. The feedback loops handle cache-invalidation and retry. These runtime behaviors shape how the system responds to load, failures, and configuration changes.

What design patterns does saleor use?

5 design patterns detected: DataLoader Pattern, Plugin Hook System, Manifest-Based Installation, Domain Module Architecture, Token-Based App Authentication.

Analyzed on April 20, 2026 by CodeSea. Written by .