Skip to content
STACK IT FAST

Directus

Curated OSSClassicHeadless CMS20+ people

Audited from github.com/directus/directus

Directus wraps any supported SQL database (Postgres, MySQL, MariaDB, SQL Server, Oracle, SQLite, CockroachDB) with auto-generated REST and GraphQL APIs and a Vue-based admin Studio, adding auth, field-level permissions, and a native MCP server for AI agents.

Language
TypeScript
Database
PostgreSQL
Hosting
Docker
Running for
8 years
Team
20+ people

Why this architecture

A Knex-based query layer and adapter packages for storage keep the same API and Studio working across many SQL vendors and object stores, while extension code runs inside an isolated-vm sandbox so third-party hooks cannot destabilize the main API process.

Tech stack by layer

9 technologies · audited Sep 17, 2026
Frontend & UI
  • VueRenders the admin Studio (the "app"); a single-page app built with the Composition API.
  • ViteDev server and production bundler for the app package (vite build / vite --host scripts).
  • PiniaClient-side store for the Studio (auth, collections, fields, permissions state).
  • Vue RouterClient-side routing between Studio modules (Content, Users, Settings, Insights).
Backend & APIs
  • ExpressHTTP server for the @directus/api package; middleware and routes registered under api/src.
  • Knex.jsSQL query builder underlying the database abstraction; drivers configured for pg, mysql2, sqlite3, oracledb, mssql.
  • GraphQLgraphql-compose and graphql-ws expose an auto-generated GraphQL API and subscriptions alongside REST.
  • isolated-vmSandboxes user-authored extension code (hooks, endpoints, operations) away from the host process.
Data & Persistence
  • PostgreSQLPrimary supported database driver via the pg package; also the default in the local dev compose file.
  • MySQL / MariaDB / SQLite / MSSQL / Oracle / CockroachDBAdditional database vendors Directus wraps through Knex adapters, each spun up in the debug compose file.
  • Redisioredis client backs caching and pub/sub for schema-cache invalidation across instances.
Infrastructure & Deploy
Tooling, Testing & Ops
  • Native MCP serverExposes Directus data and actions to MCP-compatible AI clients (Claude, Cursor) under the same permission model as human users.(inferred)
  • AI SDK (@ai-sdk/*)Powers the in-Studio AI Assistant for content creation, translation, and workflow actions.

Directus architecture diagram

Open SVG
Directus architecture diagramStudio → @directus/api (REST); Apps & SDK → @directus/api (REST); Apps & SDK → GraphQL (GraphQL); AI clients → @directus/api (MCP); GraphQL → @directus/api (resolvers); @directus/api → Your database (Knex); @directus/api → Redis (schema cache); @directus/api → Extensions (hooks · endpoints); @directus/api → Asset storage (files)CLIENTSSERVICESWORKERS & JOBSDATA & STORAGEEXTERNALStudioVue · PiniaApps & SDKREST · GraphQLAI clientsMCP@directus/apiExpress · KnexGraphQLgraphql-compose · wsExtensionsisolated-vmYour databasePostgres · MySQL · SQLite …Rediscache · pub/subAsset storageS3 · GCS · Azure · localresolversRESTRESTGraphQLMCPhooks · endpointsKnexschema cachefiles
How the main components of Directus connect, drawn from the audited repository.
Diagram as text
  • Studio (Vue · Pinia) → @directus/api (Express · Knex): REST
  • Apps & SDK (REST · GraphQL) → @directus/api (Express · Knex): REST
  • Apps & SDK (REST · GraphQL) → GraphQL (graphql-compose · ws): GraphQL
  • AI clients (MCP) → @directus/api (Express · Knex): MCP
  • GraphQL (graphql-compose · ws) → @directus/api (Express · Knex): resolvers
  • @directus/api (Express · Knex) → Your database (Postgres · MySQL · SQLite …): Knex
  • @directus/api (Express · Knex) → Redis (cache · pub/sub): schema cache
  • @directus/api (Express · Knex) → Extensions (isolated-vm): hooks · endpoints
  • @directus/api (Express · Knex) → Asset storage (S3 · GCS · Azure · local): files

Key architectural decisions

6 decisions
  1. 01

    The database layer is Knex-based, not a heavier ORM

    api/package.json depends on knex plus driver packages (pg, mysql2, sqlite3, oracledb, mssql) rather than an ORM like Prisma or TypeORM, so Directus can introspect and wrap any of these SQL dialects with the same query-builder abstraction instead of generating a schema per vendor.

  2. 02

    Studio, API, and SDK are separate pnpm workspace packages that compose into one server

    app/ (Vue Studio), api/ (Express API), sdk/ (TypeScript client), and directus/ (the published CLI/meta-package that re-exports both) are independent packages under pnpm-workspace.yaml; directus/cli.js is what actually starts the combined server in production.

  3. 03

    Extensions execute inside an isolated-vm sandbox, not the main process

    api/package.json depends on isolated-vm so that user-authored hooks, endpoints, and operations (loaded from packages/extensions) run in a separate V8 isolate rather than directly in the API process, limiting the blast radius of third-party extension code.

  4. 04

    Storage and database backends are both adapter packages

    Six separate packages (packages/storage-driver-local, -s3, -gcs, -azure, -cloudinary, -supabase) implement the same storage interface, mirroring how Knex drivers abstract the database, so self-hosters choose object storage independently of which SQL vendor they run.

  5. 05

    The production Docker image defaults to SQLite, not Postgres

    The Dockerfile runtime stage sets ENV DB_CLIENT="sqlite3" and DB_FILENAME=/directus/database/database.sqlite as the out-of-the-box default, even though the local dev docker-compose.yml spins up Postgres, MySQL, MariaDB, MSSQL, Oracle, and CockroachDB for testing every adapter.

  6. 06

    AI and MCP access reuse the existing role-based permission system

    The README describes the native MCP server and AI Assistant as operating "under the same role-based permissions as human users," so AI access control is implemented as another consumer of the existing permissions engine rather than a parallel authorization path.

How Directus is built

How Directus is structured

Directus is a pnpm workspace (pnpm-workspace.yaml) with four top-level products and a packages/ directory of shared libraries. api/ is the Express server that generates REST and GraphQL endpoints from a connected database's schema. app/ is the Vue 3 Studio, a single-page admin UI served by Vite. sdk/ is the published TypeScript client used by both the Studio and external integrations. directus/ is the meta-package (directus/cli.js) that ties API and app together into the distributable CLI and npm package. Shared concerns live in packages/: schema, types, constants, errors, validation, env, extensions and extensions-sdk for building custom hooks/endpoints/interfaces, and six storage-driver-* packages for object storage backends.

Frontend

app/package.json builds the Studio with Vite (vite build, vite --host for dev) and Vue's Composition API, using Pinia for state and Vue Router for navigation between modules like Content, Users, and Insights. Rich editing and visualization come from a large dependency set: Editor.js plugins for the WYSIWYG editor, TipTap for rich text, MapLibre GL plus Mapbox draw/geocoder for map fields, FullCalendar for calendar views, and ApexCharts for the Insights dashboards. packages/composables and packages/stores share reusable Vue logic and Pinia stores between the Studio and extensions built with packages/extensions-sdk.

Backend & APIs

api/package.json builds the server on Express, with knex as the SQL query builder and driver packages for pg, mysql2, sqlite3, oracledb, and mssql — Directus targets whichever database the operator points it at through this single abstraction rather than an ORM tied to one dialect. graphql-compose derives a GraphQL schema from the same data model that drives REST, and graphql-ws plus ws add GraphQL subscriptions and WebSocket support. Custom server-side extensions (hooks, endpoints, operations) are loaded from packages/extensions and executed inside isolated-vm, a separate V8 isolate, so a misbehaving extension cannot crash or read memory from the main API process. Authentication support includes argon2 for password hashing and @authenio/samlify-node-xmllint for SAML SSO. The @directus/ai package and @ai-sdk/* dependencies (Anthropic, Google, OpenAI, OpenAI-compatible) implement the in-Studio AI Assistant and the native MCP server exposed via @modelcontextprotocol/sdk.

Data & persistence

PostgreSQL is the primary and default-documented database — docker-compose.yml's debug stack starts it first, on postgis/postgis so PostGIS geometry types are available for map fields — but the same knex-based layer also drives MySQL, MariaDB, SQL Server, Oracle, SQLite, and CockroachDB, each with its own service in the compose file for cross-vendor testing. ioredis provides Redis connectivity, used for schema-cache invalidation and pub/sub across horizontally scaled instances. File storage is likewise adapter-based: packages/storage-driver-local, -s3, -gcs, -azure, -cloudinary, and -supabase implement a common interface so uploads can target local disk or any of five cloud providers.

Build, test & deploy

The monorepo is built with pnpm --recursive run build, linted with ESLint (eslint-plugin-vue, typescript-eslint) and Stylelint for CSS/SCSS/Vue files, and formatted with Prettier. Changesets (.changeset/) manage versioning and release notes across the workspace packages. .github/workflows runs blackbox.yml/blackbox-pr.yml for full API integration tests against tests/blackbox, e2e.yml for Playwright-driven Studio tests under tests/e2e, codeql-analysis.yml for security scanning, and release.yml/prepare-release.yml for publishing.

Self-hosting notes

The Dockerfile is a two-stage Alpine build: a builder stage installs dependencies with pnpm fetch/pnpm install --frozen-lockfile, runs the workspace build, and uses pnpm --filter directus deploy --legacy --prod dist to produce a pruned production dist/; the runtime stage copies that output, strips npm/npx/corepack from the final image, and runs it as the non-root node user under pm2 (symlinked onto PATH for docker exec ... pm2 ... diagnostics). Out of the box the image sets DB_CLIENT=sqlite3 with the database file under /directus/database/, so a self-hoster can start the container with no external database and switch to Postgres or another vendor by overriding DB_CLIENT and connection env vars. The container exposes port 8055. docker-compose.yml in the repo root is explicitly documented as debug-only (spinning up every supported database, Redis, RustFS/S3, Azurite, and Keycloak) with a pointer to the real self-hosting compose examples in the Directus docs.

What to copy (and what not to)

The adapter pattern — one interface, many concrete implementations — is used twice here (Knex drivers for databases, storage-driver-* packages for object storage) and is worth copying whenever a project genuinely needs to support several deployment environments without forking. Running extension code inside isolated-vm rather than the host process is a solid default for any platform that lets users install third-party plugins. Shipping SQLite as the zero-config Docker default while documenting Postgres as the recommended production database is a pragmatic way to let people try the product before committing to infrastructure — but it is worth copying only if your project can tolerate SQLite's write-concurrency limits for a "just try it" path.

Sources & repo audit

Audited
Sep 17, 2026
Commit
5cf557b
License
NOASSERTION

Independent analysis of repository at github.com/directus/directus. Spotted an inaccuracy? Use the claim form to request a correction.

Show this stack on your README or website
Tech stack of Directus
[![Tech stack of Directus on STACK IT FAST](https://stackitfast.com/badge/directus.svg)](https://stackitfast.com/project/directus)

Paste it into your README. It shows your current stack and links to this page.

Use this stack

Scaffold it with your agent

Paste this prompt into Claude Code, Cursor, Windsurf or AGY to start a project with Directus's architecture.

  1. 1Copy the promptThe full markdown spec, with every layer and decision.
  2. 2Open your AI toolClaude Code, Cursor, Windsurf or Copilot, in a new repo.
  3. 3Paste and scaffoldUse it as the first instruction; review before you ship.
use-this-stack.md · 61 lines · 8.1 KB
# MISSION: Scaffold "Directus" 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 **Directus**.
---
## 1. PROJECT SPECIFICATIONS & BENCHMARK
- **Reference Architecture**: Directus
- **What It Does**: Directus wraps any supported SQL database (Postgres, MySQL, MariaDB, SQL Server, Oracle, SQLite, CockroachDB) with auto-generated REST and GraphQL APIs and a Vue-based admin Studio, adding auth, field-level permissions, and a native MCP server for AI agents.
- **Domain & Category**: Headless CMS
- **Production Scale**: 20+ people
- **Development Mode**: CLASSIC
- **Architectural Rationale**: A Knex-based query layer and adapter packages for storage keep the same API and Studio working across many SQL vendors and object stores, while extension code runs inside an isolated-vm sandbox so third-party hooks cannot destabilize the main API process.
- **Live Website Reference**: https://directus.io
- **Source Repository**: https://github.com/directus/directus
---
## 2. PRODUCTION TECH STACK
- **Full Stack Array**: Vue, TypeScript, Node.js, Express, Knex.js, PostgreSQL, GraphQL, Redis, Docker
- **Primary Language(s)**: TypeScript, Vue
- **License of the reference repo**: NOASSERTION
- **Frontend**: Vue — Renders the admin Studio (the "app"); a single-page app built with the Composition API.; Vite — Dev server and production bundler for the app package (vite build / vite --host scripts).; Pinia — Client-side store for the Studio (auth, collections, fields, permissions state).; Vue Router — Client-side routing between Studio modules (Content, Users, Settings, Insights).
- **Backend & APIs**: Express — HTTP server for the @directus/api package; middleware and routes registered under api/src.; Knex.js — SQL query builder underlying the database abstraction; drivers configured for pg, mysql2, sqlite3, oracledb, mssql.; GraphQL — graphql-compose and graphql-ws expose an auto-generated GraphQL API and subscriptions alongside REST.; isolated-vm — Sandboxes user-authored extension code (hooks, endpoints, operations) away from the host process.
- **Data & persistence**: PostgreSQL — Primary supported database driver via the pg package; also the default in the local dev compose file.; MySQL / MariaDB / SQLite / MSSQL / Oracle / CockroachDB — Additional database vendors Directus wraps through Knex adapters, each spun up in the debug compose file.; Redis — ioredis client backs caching and pub/sub for schema-cache invalidation across instances.
- **Infrastructure & deploy**: Docker — Production image builds the monorepo with pnpm, deploys the directus package, and runs it under pm2.; Storage drivers (S3, GCS, Azure, Cloudinary, Supabase, local) — Pluggable asset storage backends, each its own workspace package.; pm2 — Process manager the production Docker image runs the built directus package under.
- **Tooling, testing & ops**: Native MCP server — Exposes Directus data and actions to MCP-compatible AI clients (Claude, Cursor) under the same permission model as human users.; AI SDK (@ai-sdk/*) — Powers the in-Studio AI Assistant for content creation, translation, and workflow actions.
---
## 3. KEY ARCHITECTURAL DECISIONS (audited from https://github.com/directus/directus @ 5cf557b)
1. **The database layer is Knex-based, not a heavier ORM**: api/package.json depends on knex plus driver packages (pg, mysql2, sqlite3, oracledb, mssql) rather than an ORM like Prisma or TypeORM, so Directus can introspect and wrap any of these SQL dialects with the same query-builder abstraction instead of generating a schema per vendor.
2. **Studio, API, and SDK are separate pnpm workspace packages that compose into one server**: app/ (Vue Studio), api/ (Express API), sdk/ (TypeScript client), and directus/ (the published CLI/meta-package that re-exports both) are independent packages under pnpm-workspace.yaml; directus/cli.js is what actually starts the combined server in production.
3. **Extensions execute inside an isolated-vm sandbox, not the main process**: api/package.json depends on isolated-vm so that user-authored hooks, endpoints, and operations (loaded from packages/extensions) run in a separate V8 isolate rather than directly in the API process, limiting the blast radius of third-party extension code.
4. **Storage and database backends are both adapter packages**: Six separate packages (packages/storage-driver-local, -s3, -gcs, -azure, -cloudinary, -supabase) implement the same storage interface, mirroring how Knex drivers abstract the database, so self-hosters choose object storage independently of which SQL vendor they run.
5. **The production Docker image defaults to SQLite, not Postgres**: The Dockerfile runtime stage sets ENV DB_CLIENT="sqlite3" and DB_FILENAME=/directus/database/database.sqlite as the out-of-the-box default, even though the local dev docker-compose.yml spins up Postgres, MySQL, MariaDB, MSSQL, Oracle, and CockroachDB for testing every adapter.
6. **AI and MCP access reuse the existing role-based permission system**: The README describes the native MCP server and AI Assistant as operating "under the same role-based permissions as human users," so AI access control is implemented as another consumer of the existing permissions engine rather than a parallel authorization path.
---
## 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**:
   - Isolate interactive UI state to leaf components. Keep core pages lightweight and performant.
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 (PostgreSQL, MySQL / MariaDB / SQLite / MSSQL / Oracle / CockroachDB, Redis): 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.
Scaffolded something with this prompt?
Would you pick this stack for a headless cms project?

Frequently asked about Directus

What is Directus built with?

The API (api/) is an Express server on Node.js using Knex.js to talk to whichever SQL database you configure (Postgres, MySQL, MariaDB, SQL Server, Oracle, SQLite, or CockroachDB), while the admin Studio (app/) is a Vue 3 single-page app built with Vite and Pinia.

Does Directus need a backend?

Directus is the backend: it wraps an existing SQL database and generates REST and GraphQL APIs, auth, and permissions automatically, so you point it at a database rather than writing API code yourself; the Vue Studio is a client of that generated API.

Can I self-host Directus?

Yes. The Dockerfile builds a production image (default DB_CLIENT=sqlite3, overridable to any supported vendor) that runs under pm2 and exposes port 8055, and docker-compose.yml documents a full local stack including every supported database and Redis for development and testing.

Does Directus support GraphQL and realtime updates?

Yes. api/package.json includes graphql-compose to auto-generate a GraphQL schema from the database structure and graphql-ws plus ws for GraphQL subscriptions and WebSocket connections, alongside the REST API generated from the same schema.

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.

use-this-stack.md