directus/directus
The flexible backend for all your projects 🐰 Turn your DB into a headless CMS, admin panels, or apps with a custom UI, instant APIs, auth & more.
13 hidden assumptions · 7-stage pipeline · 7 components
Like any codebase, this fullstack makes assumptions it never checks — most are routine. The ones worth your attention are below.
Turns any SQL database into a headless CMS with instant REST/GraphQL APIs and web dashboard
Data flows through Directus in multiple paths: (1) Database schema is introspected to auto-generate APIs, (2) Admin users interact through Vue.js interface which makes API calls to modify data, (3) External applications use SDK or direct HTTP calls to access REST/GraphQL endpoints. The system maintains real-time synchronization between database changes and all connected clients through WebSocket connections.
Under the hood, the system uses 4 feedback loops, 4 data pools, 6 control points to manage its runtime behavior.
A 7-component fullstack. 2722 files analyzed. Data flows through 7 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 the api/cli module is missing, incompatible, or expects different arguments, the CLI silently fails with unclear error messages or crashes after showing update check
If Node.js version format changes (e.g., 'v22.0.0' or '22.0.0-rc1'), +nodeVersion.split('.')[0] could return NaN, causing silent version check bypass and potential runtime failures
Changing primaryKey types (e.g., '123' to 123) can cause the useItem composable to not reload data, leaving stale item data in the interface while edits apply to the wrong record
Show everything (10 more)
Query URLs longer than 8192 characters will cause HTTP 414/431 errors, and the SEARCH method fallback will always be available and accepted by the server
If this fails: If the server doesn't support SEARCH method or has different URL length limits (some proxies limit to 2048), the automatic fallback fails and complex queries become impossible to execute
app/src/composables/use-item/index.ts:MAX_QUERY_URL_LENGTH
The @ai-sdk/devtools package will be available in the node_modules when AI_DEVTOOLS_ENABLED=true, and localhost:4983 will always be available for the DevTools server
If this fails: If the DevTools package is missing or localhost:4983 is in use, AI debugging fails silently with just a warning, potentially blocking AI development workflow
api/src/ai/devtools/index.ts:doDevToolsInit
The devToolsInitPromise will complete before any AI operations need the middleware, and multiple concurrent calls to initAIDevTools won't create race conditions
If this fails: If AI operations start before initialization completes, they proceed without debugging middleware, making debugging intermittent and unreliable during system startup
api/src/ai/devtools/index.ts:initAIDevTools
The layout.setup function will return a valid Vue composition API object and won't throw exceptions during component initialization
If this fails: If a layout's setup function throws errors or returns invalid objects, the entire layout system crashes with cryptic Vue errors rather than graceful degradation
packages/composables/src/use-layout.ts:createLayoutWrapper
All components using createLayoutWrapper will only emit updates for properties that are in WRITABLE_PROPS array ['selection', 'layoutOptions', 'layoutQuery']
If this fails: If a layout tries to update non-writable props, the emit will be ignored silently, causing UI state to become inconsistent with component internal state
packages/composables/src/use-layout.ts:isWritableProp
The inquirer.prompt() will always resolve with all required properties (type, name, language, install) and EXTENSION_TYPES/EXTENSION_LANGUAGES constants are properly defined
If this fails: If inquirer is interrupted or constants are undefined, the create() function receives malformed parameters, causing extension scaffolding to fail with unclear errors
packages/create-directus-extension/lib/index.js:run
The target directory has write permissions, sufficient disk space for Directus installation, and the filesystem supports creating nested directories (uploads, extensions)
If this fails: Partial installation if disk space runs out mid-installation, or permission errors creating subdirectories after the main directory exists, leaving project in broken state
packages/create-directus-project/lib/index.js:create
The npm/yarn package manager is available in PATH and can successfully install Directus dependencies without network issues or registry authentication problems
If this fails: If package installation fails due to network, registry, or auth issues, the project folder exists but is non-functional, with no cleanup of partial state
packages/create-directus-project/lib/index.js:create
Terminal width is sufficient to display the animated bunny spinner (at least numOfSpaces + 2 characters wide) and supports Unicode emoji
If this fails: Spinner animation breaks or displays incorrectly on narrow terminals or systems without Unicode support, potentially causing terminal display corruption
packages/create-directus-project/lib/index.js:bunnyFrames
Directus will always require exactly Node.js version 22 major, hardcoded as const expectedMajor = 22, and this version requirement won't need updates for patch releases or security updates
If this fails: When Directus adds support for Node.js 24 or requires 22.5+ for security fixes, the version check becomes a false blocker, preventing valid installations
packages/create-directus-project/lib/check-requirements.js:expectedMajor
Open the standalone hidden-assumptions report for directus →
How Data Flows Through the System
Data flows through Directus in multiple paths: (1) Database schema is introspected to auto-generate APIs, (2) Admin users interact through Vue.js interface which makes API calls to modify data, (3) External applications use SDK or direct HTTP calls to access REST/GraphQL endpoints. The system maintains real-time synchronization between database changes and all connected clients through WebSocket connections.
- Database introspection — The API server connects to SQL databases using configured drivers, reads table schemas, relationships, and constraints to automatically generate REST and GraphQL endpoints without requiring migrations [Database schema → API endpoints] (config: DB_CLIENT, DB_HOST, DB_PORT +1)
- Request authentication — Incoming API requests go through authentication middleware using JWT tokens, session validation, or OAuth providers before accessing protected resources [HTTP request → Authenticated user context] (config: AUTH_PROVIDERS, SECRET, ACCESS_TOKEN_TTL)
- Permission validation — The permissions system checks user roles and item-level permissions against requested operations using the configured RBAC rules and conditional filters [Authenticated user context → Permission grants] (config: ADMIN_EMAIL, ADMIN_PASSWORD)
- Data transformation — Query results are transformed based on requested fields, applied filters, sorting, and pagination parameters before serialization to JSON or GraphQL response format [Raw database results → API response] (config: QUERY_LIMIT_DEFAULT, MAX_RELATIONAL_DEPTH)
- Admin interface interaction — The Vue.js app loads item data through useItem composable, tracks edits in reactive refs, validates changes, and saves back to API with optimistic updates and error handling [User interactions → UsableItem] (config: PUBLIC_URL)
- File storage handling — File uploads are processed through configurable storage drivers (local, S3, Azure, GCS) with automatic thumbnail generation and MIME type validation for AI processing [File uploads → Stored files] (config: STORAGE_LOCATIONS, STORAGE_LOCAL_ROOT, STORAGE_LOCAL_DRIVER)
- Extension execution — Custom extensions (hooks, interfaces, panels) are loaded and executed at runtime, extending core functionality through the extension registry and SDK [Extension configurations → Extended functionality] (config: EXTENSIONS_PATH, EXTENSIONS_AUTO_RELOAD)
Data Models
The data structures that flow between stages — the contracts that hold the system together.
app/src/composables/use-item/index.tsTypeScript interface with edits: Ref<Item>, hasEdits: ComputedRef<boolean>, item: Ref<T | null>, permissions: UsablePermissions, loading/saving/deleting state flags, and methods for save/remove/archive operations
Created when editing items in admin interface, tracks changes in edits ref, validates and persists to database through API calls
packages/composables/src/use-layout.tsInterface with id: string, setup function that returns Vue component configuration, defines how data collections are displayed in different views (table, cards, map, etc.)
Registered as extension, wrapped by createLayoutWrapper to create Vue components with standardized props and emits
packages/env/src/constants/defaults.tsTypeScript interface defining all environment variables with types - includes HOST: string, PORT: number, DATABASE config, storage settings, rate limiting, and feature flags with comprehensive defaults
Loaded at startup from .env files, merged with defaults, used throughout system for configuration
packages/ai/src/files.tsUnion type of allowed MIME types: 'image/jpeg' | 'image/png' | 'image/gif' | 'image/webp' | 'application/pdf' | 'text/plain' | 'audio/mpeg' | 'audio/wav' | 'video/mp4'
Used to validate file uploads before processing by AI models, ensures only supported formats are accepted
packages/constants/src/activity.tsEnum with values CREATE, UPDATE, DELETE, REVERT, VERSION_SAVE, COMMENT, UPLOAD, LOGIN, LOGOUT, RUN, INSTALL - tracks all user and system activities
Created whenever users or system perform actions, stored in activity log for audit and history tracking
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
Primary data store containing user content, system configuration, permissions, and activity logs - abstracted through database drivers
Configurable file storage backend supporting local filesystem, S3, Azure Blob, GCS with automatic organization and metadata tracking
Runtime registry of loaded extensions including hooks, interfaces, panels, and modules with hot-reload capabilities
Centralized configuration store merging environment variables with defaults, controlling all system behavior
Feedback Loops
- Schema synchronization (polling, balancing) — Trigger: Database schema changes detected. Action: Re-introspect database schema and update API endpoints. Exit: Schema matches cached version.
- Extension hot-reload (cache-invalidation, balancing) — Trigger: Extension files modified in development. Action: Reload extension registry and reinitialize components. Exit: Extensions loaded and stable.
- Real-time synchronization (polling, reinforcing) — Trigger: Data changes in database. Action: Broadcast updates to connected WebSocket clients. Exit: All clients synchronized.
- Item validation loop (retry, balancing) — Trigger: Validation errors in useItem composable. Action: Re-validate form data and display errors to user. Exit: All validations pass or user cancels.
Delays
- Database introspection (async-processing, ~Varies by database size) — API endpoints not available until schema fully loaded
- Extension compilation (compilation, ~Seconds to minutes) — Extensions unavailable until build completes
- File upload processing (async-processing, ~Depends on file size and storage backend) — File operations blocked during upload and thumbnail generation
- AI model initialization (warmup, ~Variable based on model size) — AI features unavailable during model loading
Control Points
- Database connection (env-var) — Controls: Which database system to connect to and how. Default: DB_CLIENT, DB_HOST, DB_PORT environment variables
- Authentication providers (env-var) — Controls: Which authentication methods are available (local, OAuth, SSO). Default: AUTH_PROVIDERS configuration
- Storage backend selection (env-var) — Controls: File storage destination (local, S3, Azure, GCS). Default: STORAGE_LOCATIONS=local, STORAGE_LOCAL_DRIVER=local
- Rate limiting (feature-flag) — Controls: API request throttling and abuse prevention. Default: RATE_LIMITER_ENABLED=false by default
- AI DevTools (feature-flag) — Controls: AI debugging and monitoring in development. Default: AI_DEVTOOLS_ENABLED environment variable
- Query depth limits (threshold) — Controls: Maximum relational depth and complexity of API queries. Default: MAX_RELATIONAL_DEPTH=10, QUERY_LIMIT_DEFAULT=100
Technology Stack
Runtime environment for the backend API server and CLI tools
Frontend framework for the admin dashboard interface with reactive data binding
Primary language providing type safety across packages and API contracts
HTTP server framework handling REST API requests and middleware
Query language providing flexible data fetching alongside REST APIs
Data persistence supporting PostgreSQL, MySQL, SQLite, MariaDB, Oracle, CockroachDB, MS-SQL
SQL query builder providing database abstraction layer
State management for Vue.js admin interface
Real-time communication between server and clients for live updates
Containerization for easy deployment as shown in docker-compose.yml
Key Components
- useItem (orchestrator) — Central composable that manages complete item lifecycle in admin interface - loading, editing, validation, saving, deleting, archiving with permission checks and error handling
app/src/composables/use-item/index.ts - createLayoutWrapper (factory) — Creates Vue component wrappers for layout configurations with standardized props, emits, and reactive state management for different collection views
packages/composables/src/use-layout.ts - useEnv (registry) — Provides type-safe access to environment variables with validation and defaults, central configuration point for entire system
packages/env/src/index.ts - initAIDevTools (factory) — Initializes AI debugging middleware for development environments, enables monitoring and debugging of language model calls
api/src/ai/devtools/index.ts - checkRequirements (validator) — Validates Node.js version compatibility before project creation, ensures runtime requirements are met
packages/create-directus-project/lib/check-requirements.js - create (orchestrator) — Main project creation orchestrator that validates directory, creates folder structure, installs dependencies with animated progress feedback
packages/create-directus-project/lib/index.js - run (orchestrator) — Interactive CLI orchestrator for extension scaffolding using inquirer prompts to collect extension type, name, language preferences
packages/create-directus-extension/lib/index.js
Package Structure
Main CLI entry point that checks for updates and delegates to the API server
Core backend server providing REST/GraphQL APIs, authentication, and database abstraction
Vue.js admin dashboard for content management with AI integration and item editing
TypeScript SDK for connecting to Directus APIs with authentication and GraphQL support
AI integration utilities with file type validation and model abstractions
Vue composables for collection management, layouts, and reactive state
Shared constants for activities, extensions, fields, and permissions
CLI tool for scaffolding new Directus extensions with interactive prompts
CLI tool for bootstrapping new Directus projects with directory setup and dependency installation
Environment variable management with type-safe defaults and validation
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaCompare directus
Related Fullstack Repositories
Frequently Asked Questions
What is directus used for?
Turns any SQL database into a headless CMS with instant REST/GraphQL APIs and web dashboard directus/directus is a 7-component fullstack written in TypeScript. Data flows through 7 distinct pipeline stages. The codebase contains 2722 files.
How is directus architected?
directus is organized into 4 architecture layers: Database Abstraction Layer, Admin Interface Layer, Integration Layer, Extension Ecosystem. Data flows through 7 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.
How does data flow through directus?
Data moves through 7 stages: Database introspection → Request authentication → Permission validation → Data transformation → Admin interface interaction → .... Data flows through Directus in multiple paths: (1) Database schema is introspected to auto-generate APIs, (2) Admin users interact through Vue.js interface which makes API calls to modify data, (3) External applications use SDK or direct HTTP calls to access REST/GraphQL endpoints. The system maintains real-time synchronization between database changes and all connected clients through WebSocket connections. This pipeline design reflects a complex multi-stage processing system.
What technologies does directus use?
The core stack includes Node.js (Runtime environment for the backend API server and CLI tools), Vue.js (Frontend framework for the admin dashboard interface with reactive data binding), TypeScript (Primary language providing type safety across packages and API contracts), Express.js (HTTP server framework handling REST API requests and middleware), GraphQL (Query language providing flexible data fetching alongside REST APIs), Multiple SQL Databases (Data persistence supporting PostgreSQL, MySQL, SQLite, MariaDB, Oracle, CockroachDB, MS-SQL), and 4 more. This broad technology surface reflects a mature project with many integration points.
What system dynamics does directus have?
directus exhibits 4 data pools (SQL Database, File Storage), 4 feedback loops, 6 control points, 4 delays. The feedback loops handle polling and cache-invalidation. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does directus use?
5 design patterns detected: Database Abstraction Pattern, Extension Plugin Architecture, Composable State Management, Environment-Driven Configuration, CLI Tool Generation.
How does directus compare to alternatives?
CodeSea has side-by-side architecture comparisons of directus with strapi, payload. These comparisons show tech stack differences, pipeline design, system behavior, and code patterns. See the comparison pages above for detailed analysis.
Analyzed on April 20, 2026 by CodeSea. Written by Karolina Sarna.