
Directus: When Your 'Headless CMS' is Really Just Your Database
Tired of syncing your database schema with your CMS? Directus flips the script, turning any SQL database into a powerful headless CMS and app builder. No more duplicating efforts, just a direct line to your data.
by Sunil Band
Your Database is the Source of Truth. Why Isn't Your CMS?
We've all been there: you design a pristine database schema, build out your application logic, and then, inevitably, you need a way for non-developers to manage content. What's the go-to solution? A headless CMS. You spend days defining content models, replicating your database structure, and writing API wrappers. It feels like you're building the same thing twice, just with different tools.
This duplication isn't just annoying; it's a source of bugs. Schema drift between your database and CMS means manual updates, potential data inconsistencies, and a higher cognitive load for the team. What if your database was your CMS? What if you could get all the benefits of a powerful content management system, complete with a beautiful admin panel and instant APIs, directly from your existing SQL database?
That's where Directus comes in. It's not just another headless CMS; it's a data platform. Directus connects directly to your SQL database, introspects its schema, and provides a real-time API and an intuitive admin interface for managing that data. You're not defining content models in Directus; you're just defining your database schema, and Directus exposes it.
The Directus Philosophy: Data-First
The core idea behind Directus is simple yet profound: your database schema is your content model. When you connect Directus to a new or existing SQL database, it reads your tables, columns, and relationships. It then automatically generates a comprehensive API (REST and GraphQL) and a dynamic admin application (the Data Studio) that allows users to create, read, update, and delete data directly in your database.
This data-first approach means several things. First, there's no proprietary data storage. Your data lives where it always has. Second, any changes you make directly to your database schema are immediately reflected in Directus. Add a column? It appears in the API and Data Studio. Change a data type? Directus picks it up. This eliminates the dreaded schema sync dance.
It's a powerful shift for full-stack developers. Instead of thinking about your CMS as a separate service that your application integrates with, you can think of Directus as an extension of your database. It's the user interface and API layer for your database, designed for managing structured content and data.
Getting Started: A Project Example
Let's spin up Directus and see this in action. We'll set up a simple products table in a PostgreSQL database and watch Directus bring it to life.
First, you need a database. I'll use Docker to quickly get a PostgreSQL instance running:
docker run --name directus-db -e POSTGRES_DB=directus -e POSTGRES_USER=directus -e POSTGRES_PASSWORD=directus -p 5432:5432 -d postgresNow, let's get Directus itself. The easiest way is via npx or Docker. I prefer Docker for self-hosting in production, but npx is great for local development:
mkdir my-directus-project
cd my-directus-project
npx directus initThe npx directus init command will walk you through setting up your project. When prompted for the database, choose PostgreSQL and enter the connection details for the Docker container we just started (host: localhost, port: 5432, user: directus, password: directus, database: directus).
After initialization, start Directus:
npx directus startDirectus will now be running, typically on http://localhost:8055. Open that in your browser, and you'll be prompted to create an admin user. Do that, and you're in the Data Studio.
Creating Your First Collection (Table)
Inside the Data Studio, navigate to "Data Model". Since our directus database is initially empty (apart from Directus's own system tables), you won't see any content collections. Let's create a products table directly in our PostgreSQL database using psql or any database client:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
stock INTEGER DEFAULT 0,
image_url VARCHAR(255),
published_on TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
INSERT INTO products (name, description, price, stock, image_url) VALUES
('Wireless Headphones', 'Premium over-ear headphones with active noise cancellation.', 199.99, 50, 'https://example.com/headphones.jpg'),
('Smartwatch Pro', 'Fitness tracking, heart rate monitor, and notifications.', 249.00, 120, 'https://example.com/smartwatch.jpg');Now, refresh the Directus Data Studio. You'll see products automatically appear under "Data Model" as a new collection. Directus has introspected the table, inferred data types, and is ready for you to use it.
Managing Data and Access
Click on the products collection. You'll see the two products we inserted, displayed beautifully in a table. You can now:
- Add new items: Click "Create New" to add more products via a form generated based on your table schema.
- Edit existing items: Click on a product to open an edit form.
- Customize fields: In the Data Model, click on
productsand then on individual fields. Here, you can change how Directus presents the data (e.g., use a rich text editor fordescription, an image upload interface forimage_url) without altering your underlying database schema. This is where Directus adds its powerful CMS-like capabilities. - Set up permissions: Under "Settings > Roles & Permissions", you can define granular access control for different roles (e.g.,
Public,Admin, or custom roles likeEditor). This allows you to control who can read, create, update, or delete data in yourproductscollection, down to individual fields.
Accessing Data via API
Directus automatically exposes a REST and GraphQL API for all your collections. For our products collection, you can hit the REST endpoint:
curl http://localhost:8055/items/productsThis will return a JSON array of your products. You can also filter, sort, paginate, and relate data using standard API parameters. For example, to get only published products with stock greater than 0:
curl "http://localhost:8055/items/products?filter[stock][_gt]=0&filter[published_on][_nnull]=true"The GraphQL API offers even more flexibility for complex queries. Directus provides a built-in GraphQL playground (usually at http://localhost:8055/graphql) where you can explore your schema and test queries.
Beyond Simple Tables: Relationships and Customization
Directus truly shines when you have more complex data models. If you add another table, say categories, and create a foreign key relationship between products and categories in your database, Directus will automatically detect this relationship. In the Data Studio, you'll then be able to link products to categories using a dropdown or a multi-select interface.
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE
);
ALTER TABLE products
ADD COLUMN category_id INTEGER REFERENCES categories(id);
INSERT INTO categories (name) VALUES
('Electronics'),
('Wearables'),
('Accessories');
UPDATE products SET category_id = (SELECT id FROM categories WHERE name = 'Electronics') WHERE name = 'Wireless Headphones';
UPDATE products SET category_id = (SELECT id FROM categories WHERE name = 'Wearables') WHERE name = 'Smartwatch Pro';After refreshing the Data Studio, you'll see the category_id field in products transform into a relational picker, allowing you to easily assign categories. The API will also let you fetch nested data, like products?fields=*,category.name.
Directus also supports custom interfaces. If the default input types aren't enough, you can write your own custom Vue.js components to render and interact with specific fields, giving you full control over the editing experience.
Trade-offs and Considerations
While Directus is incredibly powerful, it's not a silver bullet. Here are a few things to keep in mind:
- Database Coupling: The strength of Directus (direct database connection) is also its potential weakness. If you're not careful, Directus's admin interface can expose your entire database schema. Granular permissions are crucial. Also, if your database schema is highly optimized for complex application logic and not content management, Directus might not provide the ideal editing experience out of the box.
- Performance: For extremely high-traffic, read-heavy scenarios, an ORM-based headless CMS might offer more built-in caching layers specific to its data storage. Directus relies on standard database optimizations and caching at the API gateway level. For most applications, this is perfectly fine, but it's something to monitor.
- No Schema Migrations: Directus doesn't do database migrations. It expects you to manage your database schema (e.g., with tools like Flyway, Liquibase, or Prisma Migrate) and then it adapts. This is by design, reinforcing the idea that your database is the source of truth, not Directus. If you're looking for a tool that handles both content management and database migrations in one, this isn't it.
- Learning Curve: While the basics are simple, mastering Directus's full capabilities (custom interfaces, hooks, flows, granular permissions) requires some dedication. It's a comprehensive platform, and understanding its underlying philosophy helps a lot.
Wrapping up
Directus offers a compelling alternative to traditional headless CMS solutions, especially for projects where the database is already the central hub of information. By treating your SQL database as the primary source, it eliminates schema duplication, streamlines development, and provides a robust, extensible platform for managing your data.
If you're tired of fighting with content models that diverge from your actual database, give Directus a serious look. The next step? Head over to the Directus documentation and try connecting it to an existing project's database. You might be surprised how quickly you can get a functional admin panel and API up and running without writing a single line of backend code.

When Your UI Needs to Break the Flat Screen: React and 3D with React Three Fiber
We've been building UIs on flat screens for decades. But what happens when you need something more? When data visualization demands depth, or an interactive product showcase needs a real sense of presence? React Three Fiber is the tool that lets you bring the full power of Three.js into your React a

When Your State Management Needs to Stop Thinking in Actions and Start Mutating
Many state management libraries force you into an 'actions and reducers' pattern. While powerful, it often adds unnecessary boilerplate for simple updates. Sometimes, you just need to directly modify state, and mutators offer a more ergonomic and intuitive approach, especially for deeply nested data

When Next.js Cache Components Refuse to Build Your App
Next.js 16.3 introduced 'Cache Components' to optimize server-side rendering, but getting them to work can be a headache. I spent a frustrating afternoon debugging why a simple page wouldn't build, only to uncover some subtle yet critical design considerations. It turns out, this feature forces you


















