saleor/saleor
Saleor Core: the high performance, composable, headless commerce API.
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".
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
Tokens could be matched to wrong apps during authentication, leading to permission escalation or wrong app context in requests
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)
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
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
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
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
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
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
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
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
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.
- 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]
- Route GraphQL Operation — GraphQL schema parses query/mutation, validates against schema definition, routes to appropriate resolver in domain modules like product, order, checkout
- 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
- Execute Business Logic — Domain resolvers execute business rules, call PluginsManager hooks for taxes/payments/validation, modify database state, prepare response data
- Dispatch Webhook Events — Business operations trigger webhook events that are queued and dispatched asynchronously to registered app endpoints with payload signing and retry logic
- 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.
saleor/app/models.pyDjango 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
saleor/graphql/app/dataloaders/app.pydataclass 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
saleor/checkout/fetch.pydataclass 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
saleor/core/taxes.pydataclass 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
saleor/payment/interface.pyDjango 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
saleor/app/manifest_schema.pyPydantic 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
Primary data store for all commerce entities, app registrations, permissions, and transactional state
In-memory cache of batched database query results during single GraphQL request lifecycle
Redis/memory cache of validated app tokens to avoid repeated hash validation
Celery task queue for asynchronous webhook delivery with retry logic
Feedback Loops
- Token Cache Invalidation (cache-invalidation, balancing) — Trigger: Invalid token detected during authentication. Action: AppByTokenLoader.remove_not_valid_tokens_from_cache removes stale cache entries. Exit: Cache cleared for invalid tokens.
- Webhook Retry Loop (retry, balancing) — Trigger: Failed webhook delivery to app endpoint. Action: Celery retries delivery with exponential backoff up to max attempts. Exit: Successful delivery or max retries exceeded.
- DataLoader Batching (cache-invalidation, balancing) — Trigger: New GraphQL request starts. Action: DataLoader creates fresh cache for request lifecycle, batches database queries. Exit: Request completes and cache is discarded.
Delays
- App Manifest Fetching (async-processing, ~HTTP request timeout) — App installation waits for remote manifest download and validation
- Webhook Delivery (async-processing, ~Variable based on app response time) — Business events are delivered asynchronously, apps may process them with delay
- Token Cache TTL (cache-ttl, ~30 days) — App tokens remain cached for 30 days before requiring database revalidation
Control Points
- Database Connection Name (env-var) — Controls: Which database connection to use for checkout operations, enables read replicas. Default: settings.DATABASE_CONNECTION_DEFAULT_NAME
- Cache Timeout (threshold) — Controls: How long app tokens remain cached before database revalidation. Default: 30 days
- App Activation State (runtime-toggle) — Controls: Whether installed apps can authenticate and receive webhooks. Default: is_active field per app
- Plugin Configuration (feature-flag) — Controls: Which payment gateways, tax providers, and extensions are enabled. Default: Plugin registry settings
Technology Stack
Provides web framework, ORM, and admin interface for the commerce platform
Single API endpoint for all commerce operations with type-safe schema and batched queries
Primary database storing all commerce data, app configurations, and transactional state
Asynchronous task queue for webhook delivery and background processing
Validates app manifests and API schemas during installation and request processing
Caches app authentication tokens and DataLoader query results
Key Components
- AppByTokenLoader (loader) — Authenticates incoming app tokens by looking up Apps from raw tokens with caching and hash validation against stored credentials
saleor/graphql/app/dataloaders/app.py - PluginsManager (orchestrator) — Coordinates execution of plugin hooks across all registered plugins for payments, taxes, webhooks, and business logic extensions
saleor/plugins/manager.py - install_app (processor) — Handles complete app installation workflow - fetches manifest, validates permissions, creates App instance, sets up webhooks, generates tokens
saleor/app/installation_utils.py - clean_manifest_data (validator) — Validates app manifests against schema requirements, checks Saleor version compatibility, validates webhook subscriptions and permission requests
saleor/app/manifest_validations.py - GraphQL Schema (gateway) — Unified GraphQL endpoint that routes queries/mutations to domain-specific resolvers while handling authentication, permissions, and data loading
saleor/graphql/ - DataLoader (optimizer) — Batches and caches database queries during GraphQL request processing to prevent N+1 query problems
saleor/graphql/core/dataloaders/ - WebhookDispatcher (dispatcher) — Delivers webhook events to registered app endpoints with retry logic, payload signing, and delivery tracking
saleor/webhook/ - AppToken (registry) — Stores hashed authentication tokens for apps with metadata about permissions and last usage
saleor/app/models.py
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated 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 Karolina Sarna.