Medusa is an open-source commerce platform: a Node.js and TypeScript server (packages/medusa, packages/core/framework) persisting to PostgreSQL via MikroORM and wired together with the Awilix DI container, plus a bundled React admin dashboard.
- Language
- TypeScript
- Database
- PostgreSQL
- Running for
- 5 years 3 months
- Team
- 20+ people
Why this architecture
Splitting commerce logic into independently versioned @medusajs packages, backed by a pluggable workflow engine (in-memory for development, Redis and BullMQ for production), lets teams customize or replace individual modules without forking the whole platform.
Tech stack by layer
7 technologies · audited Sep 17, 2026- ReactRenders the admin dashboard (packages/admin/dashboard) bundled with every Medusa install.
- ViteDev server and preview build for the admin dashboard; production bundling uses tsup.
- React RouterClient-side routing for the admin dashboard single-page app.
- Radix UIHeadless component primitives underlying the admin dashboard UI kit.
- TanStack QueryData fetching and caching layer for the admin dashboard against the Medusa API.
- TanStack TablePowers sortable, paginated data tables in the admin dashboard.
- i18nextLocalizes admin dashboard UI strings across supported languages.
- Node.jsRuns the core commerce server built from packages/medusa and packages/core/framework.
- MikroORMMaps commerce entities to PostgreSQL and drives schema migrations via the medusa-mikro-orm CLI.
- PostgreSQLPrimary datastore, accessed through the pg driver bundled in the shared deps package.
- AwilixDependency-injection container that wires modules and services together at runtime.
- ZodValidates workflow and module input schemas across the framework package.
- BullMQBacks the Redis-based workflow engine module that persists and retries long-running workflow steps.
- RedisQueue store for the ioredis-backed workflow engine module used to make workflows durable.
- JestUnit and integration test runner used across packages and integration-tests/.
- Claude CodeRepo ships Claude Code skill, agent, and command configs plus CLAUDE.md and memory/MEMORY.md.
- GitHub ActionsRuns docs automation, OpenAPI checks, admin i18n validation, and release workflows.
Medusa architecture diagram
Open SVGDiagram as text
- Admin dashboard (React · TanStack Query) → Medusa server (Node.js · Awilix): Admin API
- Storefronts (your frontend) → Medusa server (Node.js · Awilix): Store API
- Medusa server (Node.js · Awilix) → Commerce modules (orders · inventory · pricing): DI (Awilix)
- Commerce modules (orders · inventory · pricing) → PostgreSQL (MikroORM): MikroORM
- Medusa server (Node.js · Awilix) → Workflow engine (BullMQ (Redis module)): run workflows
- Workflow engine (BullMQ (Redis module)) → Redis (workflow queue): persist · retry
- Storefronts (your frontend) → Search (Algolia (optional)): instantsearch
Key architectural decisions
6 decisions- 01
Admin dashboard ships as a separate React SPA package
packages/admin/dashboard is its own workspace package built with Vite and tsup rather than living inside packages/medusa, so the API server and the admin UI can be versioned, built, and deployed independently.
- 02
Dependency injection replaces manual service wiring
packages/deps/package.json bundles awilix as the DI container that packages/core/framework uses to resolve modules and services, so commerce modules are registered and injected rather than imported and instantiated directly.
- 03
Workflows persist through a pluggable orchestration engine
packages/core/workflows-sdk defines the workflow composer, and two interchangeable engine modules implement it: packages/modules/workflow-engine-inmemory for development and packages/modules/workflow-engine-redis (bullmq plus ioredis) for durable, retryable production workflows.
- 04
PostgreSQL and MikroORM are fixed data-layer choices
packages/deps/package.json pins @mikro-orm/postgresql, @mikro-orm/knex, and pg as direct dependencies consumed by packages/core/framework, so every Medusa module persists through the same ORM and database engine rather than choosing its own.
- 05
Commerce logic is split into independently publishable modules
packages/modules/* (for example api-key, workflow-engine-redis) and packages/core/* (core-flows, orchestration, query) are separate npm packages under the @medusajs scope, each with its own package.json, so modules can be depended on individually outside the core server.
- 06
A CLI scaffolds new projects instead of a template repo
packages/cli/create-medusa-app is a published npm package (create-medusa-app) that uses inquirer, boxen, and wait-on to interactively scaffold a new Medusa application, similar to create-react-app rather than a git-cloned starter.
How Medusa is built
How Medusa is structured
Medusa is a yarn workspace monorepo (package.json, .yarnrc.yml) built and tested through Turborepo (turbo.json). The commerce server lives in packages/medusa, which depends on packages/core/framework for configuration, database access, workflows, jobs, HTTP handling, and telemetry — the framework package's exports map (./config, ./database, ./workflows, ./search, ./http, ./telemetry) shows how those concerns are split into importable subpaths. Shared low-level dependencies (MikroORM, PostgreSQL driver, Awilix, Zod, OpenTelemetry) are centralized in packages/deps, so every module resolves them from one place instead of each declaring its own version. Commerce capabilities are further split into packages/modules/* (for example api-key, workflow-engine-redis, workflow-engine-inmemory) and packages/core/* (core-flows, orchestration, query, js-sdk, modules-sdk, workflows-sdk), each an independently versioned @medusajs/* npm package. The admin UI (packages/admin/dashboard) and a project-scaffolding CLI (packages/cli/create-medusa-app) round out the packages tree, and www/ holds the separate documentation site (its own Turborepo workspace).
Backend & APIs
The server is plain Node.js and TypeScript, not built on an external HTTP framework package visible in the audited manifests — packages/core/framework's ./http and ./api exports and packages/medusa's api-key/subscribers/jobs subpaths indicate the framework owns routing, subscribers, and scheduled jobs internally. Modules are registered and resolved through Awilix (packages/deps/package.json dependency awilix), which is Medusa's dependency-injection container: instead of a module importing another module's implementation directly, both are resolved from the Awilix container that packages/core/framework configures at boot. packages/core/query implements a "remote query and joiner" used to compose data across modules without direct database joins between module boundaries. Long-running or multi-step operations (for example checkout or fulfillment flows) are written as workflows using the composer exported from packages/core/workflows-sdk (./composer subpath) and the step library in packages/core/core-flows.
Data & persistence
PostgreSQL is the only database engine wired into the shared deps package: packages/deps/package.json depends directly on @mikro-orm/postgresql, @mikro-orm/knex, @mikro-orm/migrations, and pg. packages/core/framework re-exports these under ./mikro-orm/* subpaths (cli, core, knex, migrations, postgresql) and ships a medusa-mikro-orm CLI binary for running migrations against a project's database. Because the ORM and driver live in the shared deps package rather than in each module, every commerce module (orders, inventory, pricing, and so on) persists through the same MikroORM/PostgreSQL stack rather than picking its own. For workflow state, packages/modules/workflow-engine-redis adds a second persistence path: it depends on bullmq and ioredis to store workflow execution state and retries in Redis, which is the production-recommended configuration; packages/modules/workflow-engine-inmemory keeps that same state in process memory for local development, with no external dependency.
Frontend
packages/admin/dashboard (published as @medusajs/dashboard) is a React single-page application, not a server-rendered app — its dev/preview scripts run Vite directly, and production builds go through tsup (yarn typecheck && yarn run -T tsup) with a separate build:vite target for a standalone preview bundle. Dependencies show a fairly standard SPA admin stack: react-router-dom for routing, @tanstack/react-query and @tanstack/react-table for server-state and table data, radix-ui/@radix-ui/react-dialog for accessible primitives, @medusajs/ui and @medusajs/icons for the design system, i18next/react-i18next for localization, react-hook-form for forms, and zod for schema validation shared with the backend. The dashboard consumes the API through @medusajs/js-sdk (packages/core/js-sdk), a thin client built on fetch-event-stream, which is also what third-party admin extensions and storefronts are expected to use.
Build, test & deploy
Backend packages compile with tsc --build (see the watch/build scripts in packages/medusa and packages/core/framework), coordinated across the workspace by turbo.json's build pipeline, which depends on upstream package builds (dependsOn: ["^build"]) before building a package itself. Tests run on Jest: packages/medusa/package.json defines separate test (unit, testPathPattern=src) and test:integration scripts, and the root integration-tests/jest.config.js plus integration-tests/package.json drive end-to-end suites against a real database, referenced by the test-cli-with-database.yml workflow. .github/workflows also runs validate-http-types.yml and oas-test.yml to check generated HTTP types and the OpenAPI spec stay in sync with the code, admin-i18n-validation.yml to check dashboard translation files, and docs-automation.yml/sync-api-reference-specs-to-r2.yml to publish generated API references. No Dockerfile, fly.toml, or Vercel config appears in the audited tree for the core server, so containerization and deployment beyond docker-compose-style local setups documented outside this repository are not evidenced here.
Self-hosting notes
Because the ORM, database driver, and DI container are fixed dependencies of packages/deps, self-hosting Medusa means running a Node.js process against a PostgreSQL instance at minimum. If a deployment uses packages/modules/workflow-engine-redis for durable workflows (recommended for production per the module's description "Medusa Workflow Orchestrator module using Redis to track workflows executions"), a Redis instance is also required; otherwise packages/modules/workflow-engine-inmemory avoids that dependency at the cost of losing workflow state across restarts. packages/cli/create-medusa-app is the documented way to scaffold a new project, and packages/cli/medusa-cli provides the runtime CLI (migrations, admin build, and so on) referenced by module scripts like medusa-mikro-orm migration:up.
What to copy (and what not to)
Centralizing shared runtime dependencies (ORM, database driver, DI container, OpenTelemetry) in one internal package (packages/deps) that everything else depends on is a clean way to guarantee every module in a modular monorepo uses the same versions, and is worth copying for any multi-package backend. Splitting the workflow engine into swappable implementations behind one composer API (packages/core/workflows-sdk) — in-memory for development, Redis-backed for production — is a good pattern for making expensive infrastructure optional in local environments without branching application code. Less broadly applicable is fixing the ORM and database engine at the framework level: it simplifies Medusa's own module ecosystem, but teams building a single application rather than a module platform may not need that rigidity and could find a lighter, directly-imported ORM easier to reason about.
Sources & repo audit
- Audited
- Sep 17, 2026
- Commit
- c000d37
- License
- NOASSERTION
- Root package.json (yarn workspaces monorepo layout)
- packages/deps/package.json (MikroORM, pg, awilix, zod bundled as shared deps)
- packages/admin/dashboard/package.json (React admin SPA dependencies)
- packages/modules/workflow-engine-redis/package.json (BullMQ + ioredis workflow engine)
- turbo.json (monorepo build pipeline configuration)
Independent analysis of repository at github.com/medusajs/medusa. Spotted an inaccuracy? Use the claim form to request a correction.
Show this stack on your README or website
[](https://stackitfast.com/project/medusa)Paste it into your README. It shows your current stack and links to this page.
Scaffold it with your agent
Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Medusa's architecture.
- 1Copy the promptThe full markdown spec, with every layer and decision.
- 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
- 3Paste and scaffoldUse it as the first instruction; review before you ship.
# MISSION: Scaffold "Medusa" Production Architecture
You are an expert Senior Staff Software Architect and Full-Stack Engineer. Your mission is to scaffold and implement a production-grade, highly reliable, and modular codebase following the proven architecture of **Medusa**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Medusa
- **What It Does**: Medusa is an open-source commerce platform: a Node.js and TypeScript server (packages/medusa, packages/core/framework) persisting to PostgreSQL via MikroORM and wired together with the Awilix DI container, plus a bundled React admin dashboard.
- **Domain & Category**: E-commerce API
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: Splitting commerce logic into independently versioned @medusajs packages, backed by a pluggable workflow engine (in-memory for development, Redis and BullMQ for production), lets teams customize or replace individual modules without forking the whole platform.
- **Live Website Reference**: https://medusajs.com
- **Source Repository**: https://github.com/medusajs/medusa
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: TypeScript, Node.js, React, PostgreSQL, Redis, MikroORM, Vite
- **Primary Language(s)**: TypeScript, JavaScript
- **License of the reference repo**: NOASSERTION
- **Frontend**: React — Renders the admin dashboard (packages/admin/dashboard) bundled with every Medusa install.; Vite — Dev server and preview build for the admin dashboard; production bundling uses tsup.; React Router — Client-side routing for the admin dashboard single-page app.; Radix UI — Headless component primitives underlying the admin dashboard UI kit.; TanStack Query — Data fetching and caching layer for the admin dashboard against the Medusa API.; TanStack Table — Powers sortable, paginated data tables in the admin dashboard.; i18next — Localizes admin dashboard UI strings across supported languages.
- **Backend & APIs**: Node.js — Runs the core commerce server built from packages/medusa and packages/core/framework.; MikroORM — Maps commerce entities to PostgreSQL and drives schema migrations via the medusa-mikro-orm CLI.; PostgreSQL — Primary datastore, accessed through the pg driver bundled in the shared deps package.; Awilix — Dependency-injection container that wires modules and services together at runtime.; Zod — Validates workflow and module input schemas across the framework package.; BullMQ — Backs the Redis-based workflow engine module that persists and retries long-running workflow steps.; Redis — Queue store for the ioredis-backed workflow engine module used to make workflows durable.
- **Infrastructure & deploy**: Turborepo — Orchestrates build and test pipelines across the yarn workspace packages.; Yarn — Workspace package manager for the root and www monorepo workspaces.; Algolia — Optional search backend wired through the instantsearch-adapter package for storefront search.
- **Tooling, testing & ops**: Jest — Unit and integration test runner used across packages and integration-tests/.; Claude Code — Repo ships Claude Code skill, agent, and command configs plus CLAUDE.md and memory/MEMORY.md.; GitHub Actions — Runs docs automation, OpenAPI checks, admin i18n validation, and release workflows.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/medusajs/medusa @ c000d37)
1. **Admin dashboard ships as a separate React SPA package**: packages/admin/dashboard is its own workspace package built with Vite and tsup rather than living inside packages/medusa, so the API server and the admin UI can be versioned, built, and deployed independently.
2. **Dependency injection replaces manual service wiring**: packages/deps/package.json bundles awilix as the DI container that packages/core/framework uses to resolve modules and services, so commerce modules are registered and injected rather than imported and instantiated directly.
3. **Workflows persist through a pluggable orchestration engine**: packages/core/workflows-sdk defines the workflow composer, and two interchangeable engine modules implement it: packages/modules/workflow-engine-inmemory for development and packages/modules/workflow-engine-redis (bullmq plus ioredis) for durable, retryable production workflows.
4. **PostgreSQL and MikroORM are fixed data-layer choices**: packages/deps/package.json pins @mikro-orm/postgresql, @mikro-orm/knex, and pg as direct dependencies consumed by packages/core/framework, so every Medusa module persists through the same ORM and database engine rather than choosing its own.
5. **Commerce logic is split into independently publishable modules**: packages/modules/* (for example api-key, workflow-engine-redis) and packages/core/* (core-flows, orchestration, query) are separate npm packages under the @medusajs scope, each with its own package.json, so modules can be depended on individually outside the core server.
6. **A CLI scaffolds new projects instead of a template repo**: packages/cli/create-medusa-app is a published npm package (create-medusa-app) that uses inquirer, boxen, and wait-on to interactively scaffold a new Medusa application, similar to create-react-app rather than a git-cloned starter.
---
## 4. NON-NEGOTIABLE ARCHITECTURAL GUARDRAILS
1. **Monorepo & Modular Separation**:
- Structure as a Turborepo monorepo with strict package boundaries:
- `apps/web`: Application UI, routing, layouts, and server endpoints.
- `packages/ui`: Shared design tokens, CSS variables, and Radix UI primitive components.
- `packages/db`: Database schemas, client singleton, declarative migrations, and seed scripts.
- `packages/config`: Shared TypeScript, ESLint, and build configurations.
2. **Strict Type Safety & Zero `any` Policy**:
- Enable `strict: true`, `noImplicitAny: true`, and `strictNullChecks: true`.
- Validate ALL external inputs, API request bodies, and query parameters with **Zod** schemas before execution.
3. **Frontend & Rendering Guidelines**:
- Utilize Vite 6 with TanStack Router for fully type-safe routing. Manage server state and caching via TanStack Query v5 with optimistic UI updates.
4. **Design System & Aesthetics**:
- Keep every color, radius, shadow and font in a single token file (CSS variables) and consume tokens everywhere; never hardcode hex values in components.
- Prefer crisp 1px borders and one subtle shadow scale over blurry default shadows. Pair one sans-serif for body/headings with one monospace for tags, badges, metrics, and code.
5. **Data Layer & Reliability**:
- Write declarative schema definitions with foreign keys, composite indexes on queried filters, and automated timestamp triggers.
- Use connection pooling and prepared statements for serverless database execution.
---
## 5. STEP-BY-STEP SCAFFOLDING ROADMAP
- **Phase 1: Workspace & Root Config**: Initialize package manager, monorepo configuration (`turbo.json`, `tsconfig.base.json`, `package.json`).
- **Phase 2: Database Schema & Client**: Set up the data layer: client, connection pool, models, and migration scripts.
- **Phase 3: Design Tokens & UI Primitives**: Build accessible `Button`, `Input`, `Card`, `Badge`, and layout wrappers inside `packages/ui`.
- **Phase 4: Core Application Routes & Handlers**: Implement primary authentication, user session handling, and application routes.
- **Phase 5: Quality Assurance & Build Verification**: Run `tsc --noEmit`, ESLint, Prettier, and smoke test suites to ensure zero compilation or runtime errors.
---
## 6. EXECUTION INSTRUCTIONS
1. Review all specifications, architectural guardrails, and stack choices above.
2. Present the full monorepo directory tree structure.
3. Systematically generate the complete, production-ready codebase according to the 5-phase roadmap above — starting with the root workspace setup, followed by the database schema, UI design system package, and full-stack application routes until the repository is fully scaffolded and ready to run.Frequently asked about Medusa
What is Medusa built with?
Medusa's core server (packages/medusa, packages/core/framework) runs on Node.js and TypeScript, persists to PostgreSQL through MikroORM, and wires modules together with the Awilix dependency-injection container (packages/deps/package.json). The bundled admin dashboard is a separate React app built with Vite.
Does Medusa need a backend?
Yes, Medusa is the backend. It ships as a Node.js server (packages/medusa) exposing a commerce API; the React admin dashboard and any storefront are separate clients that call that API.
Can I self-host Medusa?
Yes. It runs as a Node.js and PostgreSQL application. Production workflow durability additionally needs Redis for the packages/modules/workflow-engine-redis module (BullMQ), while local development can use the in-memory workflow engine instead.
How does Medusa handle background or long-running work?
Long-running processes are modeled as workflows via packages/core/workflows-sdk. packages/modules/workflow-engine-redis persists and retries their steps in Redis using BullMQ, and packages/modules/workflow-engine-inmemory is the non-persistent alternative for local development.
What powers Medusa's admin dashboard?
packages/admin/dashboard is a React single-page app built with Vite, using Radix UI primitives, TanStack Query and Table, React Router, and i18next, published as the @medusajs/dashboard package.
Is Medusa written in TypeScript?
Yes. Medusa's core server (packages/medusa, packages/core/framework) is TypeScript running on Node.js, and the bundled admin dashboard is a separate React app in the same monorepo.
One email a month: new deep dives and stack trends
New source-audited architectures, head-to-head comparisons and the monthly stack report. No spam, unsubscribe anytime.
Similar architectures
- ToolJetHybridLow-Code Developer Tool Platform · 6-20 peopleShares TypeScript · React · PostgreSQL
- LagoClassicBilling & Metering Engine · 6-20 peopleShares React · PostgreSQL · Redis
- FormbricksAI-agentSurvey & Feedback SaaS · 2-5 peopleShares TypeScript · PostgreSQL · Redis
- HyperswitchClassicOpen-Source Payments Orchestration · 20+ peopleShares PostgreSQL · Redis
- PostGraphileClassicAutomated GraphQL API Engine · 2-5 PeopleShares TypeScript · Node.js · PostgreSQL
- InfisicalHybridSecret Management · 6-20 peopleShares React · TypeScript · Vite