# Directus: Instant REST and GraphQL APIs for Any SQL Database

[Directus](https://directus.io/) is an **open-source platform that connects to any SQL database and instantly exposes it through REST and GraphQL APIs**, a browser-based admin panel, role-based access control, and a no-code automation engine called Flows. It works on top of an existing schema without modifying it, so your data stays in standard SQL and can be accessed directly at any time.

## The database-first approach

Most headless CMS and backend-as-a-service platforms impose their own data schema. Directus takes the opposite approach: it introspects whatever SQL schema is already there and builds its interfaces on top of it. This means no vendor lock-in, no proprietary data format, and no migration files. Pointing Directus at an existing populated database is sufficient to start managing its data and serving it through an API.

Supported databases include PostgreSQL, MySQL, Oracle, MS-SQL, and several others.

## What Directus provides automatically

Once connected to a database, Directus generates several services without configuration:

- **REST and GraphQL APIs** for every table, with filtering, sorting, and pagination
- **Data Studio**, a no-code admin panel for managing content
- **Role-Based Access Control** configurable down to individual fields
- **Flows**, a visual no-code automation engine triggered by data events, webhooks, or schedules
- **File handling** including uploads, transformations, and a digital asset manager

## Installation

The quickest local setup uses the official CLI to scaffold a Docker Compose project:

```command
npx directus-template-cli@latest init
```

This generates a `docker-compose.yml` and a `.env` file for database credentials and the Directus secret key. Starting the stack:

```command
docker-compose up -d
```

The Directus instance is available at `http://localhost:8055` after the initial startup completes. Creating an administrator account on first visit provides access to the Data Studio.

![Clean slate of a new Directus project showing "No Collections" and a prompt to create one](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/51dff60a-6fef-42c6-0aa7-74a6ec235d00/md2x =1280x720)

## Building an order management system

The following example builds a complete order management backend including a data model, RBAC permissions, and an automated email notification, without writing any backend code.

### Designing the data model

In Directus, a **Collection** maps to a SQL table and a **Field** maps to a column. Creating a collection in the Data Studio executes `CREATE TABLE` in the database.

Creating an `orders` collection:

1. Click **Create Collection** and enter `orders` as the name. Directus suggests an auto-incremented integer `id` as the primary key.
2. Under the Optional Fields tab, enable `Created On` (renamed to `create_at`) and `Updated On` (renamed to `updated_at`).
3. Save the collection.

![The "Creating New Collection" modal where the orders collection is named and configured](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/3b113a80-d13a-4478-d88a-bef5fe14b000/lg2x =1280x720)

Adding fields to the `orders` collection:

- `customer_name`: Input field, String type, required
- `email`: Input field, String type, required
- `item`: Dropdown field with choices `Laptop`, `Headphones`, `Phone`, `Tablet`
- `amount`: Input field, Float type (to support decimal values)
- `status`: Dropdown field with choices `Pending`, `Paid`, `Shipped`

Each field creation corresponds to an `ALTER TABLE` statement. No SQL is written manually.

### Entering data

After the collection is created, the Data Studio generates a form matching the field definitions. Clicking **Create Item** opens the form with text inputs, dropdowns, and number inputs corresponding to each field type.

![Content view for the orders collection showing a table populated with three sample orders](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/a2fd1274-63c1-400b-2b05-b386e9d42700/md1x =1280x720)

### Configuring public API access

By default, the Directus API is locked down. The **Public** role governs what unauthenticated requests can do. Configuring it to allow read-only access to `orders`:

1. Navigate to **Settings > Access Policies > Public**.
2. Click **Add Collection** and select `orders`.
3. Enable the **Read** permission with **All Access**.
4. Leave Create, Update, and Delete disabled.

![Public Policy screen where permissions for the orders collection are being configured](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/bf7d8af8-855b-4fbb-fb1f-1f820ae43300/md1x =1280x720)

The REST endpoint for the collection is now publicly readable at `/items/orders`. All write operations remain protected.

### Automating email notifications with Flows

Flows is Directus's no-code automation engine. A flow consists of a trigger and one or more operations. The following flow sends an email whenever a new order is created.

Creating the flow under **Settings > Flows > Create Flow**:

- **Trigger type:** Event Hook
- **Action type:** Non-blocking (runs in the background)
- **Scope:** `items.create`
- **Collection:** `orders`

Adding a **Send Email** operation after the trigger:

- **To:** the admin notification address
- **Subject:** `You got a New Order!`
- **Body:** uses `{{$trigger.payload.*}}` syntax to reference fields from the newly created item

```text
A new order has been placed!

Customer: {{$trigger.payload.customer_name}}
Email: {{$trigger.payload.email}}
Product: {{$trigger.payload.item}}
Amount: ${{$trigger.payload.amount}}
Status: {{$trigger.payload.status}}
```

![Visual flow builder canvas showing the Trigger node connected to the Send Email operation node](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/63ddb959-16d5-4e79-9678-7faf96218800/orig =1280x720)

### Testing email delivery locally

For local testing, [Mailpit](https://mailpit.axllent.org/) can be added to the `docker-compose.yml` to capture outgoing email without a real SMTP server.

![docker-compose.yml file with the email settings for Mailpit highlighted](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/316eddb7-ba63-43f4-636b-71d9b7726b00/lg2x =1280x720)

Creating a new order after saving the flow fires the `items.create` event. The flow runs in the background and delivers the notification to the Mailpit inbox.

![Mailpit inbox showing the "You got a New Order!" email with the body containing dynamic data from the test order](https://imagedelivery.net/xZXo0QFi-1_4Zimer-T0XQ/2a02818a-44a0-43ea-5850-859b40657d00/orig =1280x720)

## Limitations and tradeoffs

Directus's visual tooling works well for CRUD-heavy applications, content management, and rapid internal tool development. For projects that are code-first by design, such as TypeScript monorepos where the data model is defined in application code, a tool like [Payload](https://payloadcms.com/) may be a better fit.

Flow operations cover common automation patterns but are not a substitute for custom application logic. Complex business rules still require code. Directus supports custom extensions written in JavaScript or TypeScript for cases where the built-in operations are insufficient.

Self-hosting transfers infrastructure responsibility, including updates and backups, to your team.

## Final thoughts

**Directus eliminates the repetitive parts of backend development: CRUD API setup, admin panel construction, authentication scaffolding**, and permission configuration. Its database-first approach means the underlying data is always portable and accessible without Directus, which removes the lock-in risk common to other BaaS platforms.

For new projects, legacy database modernization, or internal tools where shipping quickly matters more than a custom-coded backend, Directus covers a lot of ground with minimal setup.

Documentation and self-hosting guides are available at [docs.directus.io](https://docs.directus.io/).