vendurehq/vendure
Open source headless commerce framework built with TypeScript, NestJS, React and GraphQL
Open source headless commerce framework with TypeScript, NestJS, Angular admin UI
Multi-directional data flow where the core framework provides GraphQL APIs consumed by admin UIs, while plugins extend functionality through event handlers and services that interact with the core database and caching layers.
Under the hood, the system uses 3 feedback loops, 4 data pools, 5 control points to manage its runtime behavior.
Structural Verdict
A 12-component fullstack with 0 connections. 2733 files analyzed. Minimal connections — components operate mostly in isolation.
How Data Flows Through the System
Multi-directional data flow where the core framework provides GraphQL APIs consumed by admin UIs, while plugins extend functionality through event handlers and services that interact with the core database and caching layers.
- Request Processing — GraphQL requests processed by NestJS core framework with authentication and validation
- Business Logic — Core services handle commerce operations like order management, product catalog, and customer data
- Plugin Extensions — Plugins like email, assets, and jobs extend core functionality through event handlers
- Data Persistence — Entity changes persisted to database through TypeORM with migration support
- UI Rendering — Admin interfaces (Angular/React) consume GraphQL APIs to render management dashboards
- Background Processing — Job queue system handles async tasks like email sending and order fulfillment
System Behavior
How the system actually operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Cached commerce metrics calculations with SHA-1 hashed keys
Main database storing orders, products, customers, and all business entities
Background job processing queue for async tasks
File storage system for product images and documents with S3 support
Feedback Loops
- GraphQL Type Generation (auto-scale, balancing) — Trigger: Schema changes in core. Action: Regenerate types across all packages. Exit: Types synchronized.
- Metrics Refresh (cache-invalidation, balancing) — Trigger: Cache miss or refresh=true. Action: Recalculate commerce metrics from database. Exit: Metrics cached with TTL.
- Development Hot Reload (polling, reinforcing) — Trigger: File changes during development. Action: Rebuild and restart dev server. Exit: Code compilation errors.
Delays & Async Processing
- Metrics Calculation (cache-ttl, ~variable) — Admin dashboard shows cached metrics until recalculated
- Job Queue Processing (async-processing) — Background tasks like email sending processed asynchronously
- Database Migrations (scheduled-job) — Schema changes applied before server startup
- Asset Transform (async-processing) — Image resizing and optimization processed on-demand or in background
Control Points
- Plugin Configuration (env-var) — Controls: Enable/disable plugin features and set operational parameters
- Development Mode (env-var) — Controls: Production vs development build optimizations
- Job Queue Start (env-var) — Controls: Whether to start background job processing. Default: RUN_JOB_QUEUE=1
- Database Type (runtime-toggle) — Controls: Which database system to use (mysql, postgres, sqlite)
- Cache Refresh (runtime-toggle) — Controls: Force metrics recalculation bypassing cache
Package Structure
This monorepo contains 16 packages:
Main backend commerce framework with NestJS, GraphQL API, and database entities. Contains all core business logic for orders, products, customers, and payments.
Angular-based admin dashboard for managing the commerce platform. Provides UI for product management, order processing, and system configuration.
Modern React-based dashboard replacement for the Angular admin-ui, using Storybook for component development and documentation.
Command-line interface for scaffolding, code generation, and project management tasks using Commander.js.
Project scaffolding tool for creating new Vendure applications with various database and configuration options.
Development server for testing Vendure during development, includes test plugins and bootstrap configuration.
Shared utilities, types, and GraphQL type definitions used across all packages in the monorepo.
Testing utilities and helpers for writing e2e and integration tests for Vendure applications.
Plugin that provides metrics and analytics services for the admin interface, including order statistics and caching.
Handles asset storage, image transformations, and CDN integration with support for S3 and Sharp image processing.
Email system with template generation, event handling, and SMTP/SES integration using Handlebars and MJML.
Background job processing system for handling asynchronous tasks like order fulfillment and email sending.
GraphQL IDE integration plugin for API exploration and testing during development.
Security hardening plugin that implements various security measures and best practices for production deployments.
Analytics and telemetry collection plugin for monitoring system performance and usage metrics.
Development toolkit and utilities for building custom admin UI extensions and components.
Technology Stack
Backend framework for dependency injection and GraphQL API
API layer with type-safe schema and auto-generated types
Database ORM for entity management and migrations
Legacy admin UI framework with reactive forms
Modern admin dashboard with Storybook component development
Monorepo management for independent package versioning
CLI framework for development and scaffolding tools
TypeScript AST manipulation for code generation
Build tool for React dashboard development
Testing framework for unit and integration tests
Key Components
- bootstrap (function) — Bootstraps the Vendure application with configuration and starts the server
packages/dev-server/index.ts - MetricsService (service) — Calculates and caches commerce metrics like order totals and average values
packages/admin-ui-plugin/src/service/metrics.service.ts - loadAppConfig (function) — Loads Angular admin application configuration before bootstrapping
packages/admin-ui/src/main.ts - getTsMorphProject (function) — Creates TypeScript AST project for code generation and manipulation
packages/cli/src/utilities/ast-utils.ts - generated-types (type-def) — Auto-generated GraphQL types shared across all packages
packages/common/src/generated-types.ts - ImageTransformStrategy (type-def) — Defines interface for image transformation and resizing strategies
packages/asset-server-plugin/src/types.ts - EmailPluginOptions (type-def) — Configuration interface for email system with templates and handlers
packages/email-plugin/src/types.ts - vendureDashboardPlugin (plugin) — Vite plugin for React dashboard development with GraphQL codegen
packages/dashboard/.storybook/main.ts - UserResponses (type-def) — User input configuration for project scaffolding with database and feature options
packages/create/src/types.ts - registerCommands (function) — Registers all CLI commands from declarations into the Commander program
packages/cli/src/cli.ts - defineDashboardExtension (function) — Defines custom dashboard extensions with routes and components
packages/dashboard/e2e/fixtures/form-inputs-test-dashboard/index.tsx - apiExtensions (type-def) — GraphQL schema extensions for campaign and promotion management
packages/core/e2e/fixtures/test-plugins/issue-2453/api/index.ts
Configuration
docker-compose.yml (yaml)
name(string, unknown) — default: vendure-monoreposervices.mariadb.image(string, unknown) — default: mariadb:latestservices.mariadb.container_name(string, unknown) — default: mariadbservices.mariadb.environment.MARIADB_DATABASE(string, unknown) — default: vendure-devservices.mariadb.environment.MARIADB_USER(string, unknown) — default: vendureservices.mariadb.environment.MARIADB_PASSWORD(string, unknown) — default: passwordservices.mariadb.environment.MARIADB_ROOT_PASSWORD(string, unknown) — default: passwordservices.mariadb.volumes(array, unknown) — default: mariadb_data:/var/lib/mysql- +75 more parameters
graphql.config.yml (yaml)
projects.admin.schema(string, unknown) — default: ./schema-admin.jsonprojects.admin.documents(array, unknown) — default: packages/**/graphql/admin-definitions.ts,packages/**/graphql/shared-definitions.ts,packages/**/graphql/fragments-admin.tsprojects.shop.schema(string, unknown) — default: ./schema-shop.jsonprojects.shop.documents(array, unknown) — default: packages/**/graphql/shop-definitions.ts,packages/core/e2e/order-merge.e2e-spec.ts,packages/core/e2e/product-option.e2e-spec.ts
lerna.json (json)
packages(array, unknown) — default: packages/*version(string, unknown) — default: 3.6.0npmClient(string, unknown) — default: npmcommand.version.push(boolean, unknown) — default: false$schema(string, unknown) — default: node_modules/lerna/schemas/lerna-schema.json
schema-admin.json (json)
data.__schema.queryType.name(string, unknown) — default: Querydata.__schema.queryType.kind(string, unknown) — default: OBJECTdata.__schema.mutationType.name(string, unknown) — default: Mutationdata.__schema.mutationType.kind(string, unknown) — default: OBJECTdata.__schema.subscriptionType(object, unknown)data.__schema.types(array, unknown) — default: [object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]data.__schema.directives(array, unknown) — default: [object Object],[object Object],[object Object],[object Object],[object Object]
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated Fullstack Repositories
Frequently Asked Questions
What is vendure used for?
Open source headless commerce framework with TypeScript, NestJS, Angular admin UI vendurehq/vendure is a 12-component fullstack written in TypeScript. Minimal connections — components operate mostly in isolation. The codebase contains 2733 files.
How is vendure architected?
vendure is organized into 5 architecture layers: Core Framework, Admin Interfaces, Plugin Ecosystem, Developer Tools, and 1 more. Minimal connections — components operate mostly in isolation. This layered structure keeps concerns separated and modules independent.
How does data flow through vendure?
Data moves through 6 stages: Request Processing → Business Logic → Plugin Extensions → Data Persistence → UI Rendering → .... Multi-directional data flow where the core framework provides GraphQL APIs consumed by admin UIs, while plugins extend functionality through event handlers and services that interact with the core database and caching layers. This pipeline design reflects a complex multi-stage processing system.
What technologies does vendure use?
The core stack includes NestJS (Backend framework for dependency injection and GraphQL API), GraphQL (API layer with type-safe schema and auto-generated types), TypeORM (Database ORM for entity management and migrations), Angular (Legacy admin UI framework with reactive forms), React (Modern admin dashboard with Storybook component development), Lerna (Monorepo management for independent package versioning), and 4 more. This broad technology surface reflects a mature project with many integration points.
What system dynamics does vendure have?
vendure exhibits 4 data pools (Metrics Cache, Commerce Database), 3 feedback loops, 5 control points, 4 delays. The feedback loops handle auto-scale and cache-invalidation. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does vendure use?
5 design patterns detected: Plugin Architecture, GraphQL Code Generation, Dual UI Strategy, Monorepo Package Organization, Development Toolchain.
Analyzed on March 31, 2026 by CodeSea. Written by Karolina Sarna.