How to Use Directus: The Beginner's Guide (First Docker Run, Your First Collection, the Roles-First Rule, and the API Lesson)
CodexFuse Team · 2026-11-01T09:07:50.931Z · 15 min read
Run Directus with Docker, build your first collection, apply the roles-first rule, and read your own SQL database through REST or GraphQL — one beginner guide.
Learning how to use Directus takes an afternoon: run one Docker container, open the admin panel on port 8055, create your first collection, set up roles before anything goes public, and read your data through a REST or GraphQL API you never had to build. Directus is a database-first headless CMS: a Directus self-hosted setup wraps your own SQL database — SQLite by default, or your existing Postgres, MySQL, MariaDB, SQL Server, Oracle, or CockroachDB — with an instant admin app, granular role permissions, and auto-generated APIs. If you have never run a container before, our Docker beginner guide gets you to the one-command install in minutes. This Directus tutorial for beginners runs the full beginner arc in one place: first Docker run with persistence, your first collection and fields, the roles-first rule, pointing it at an existing database, and the API lesson — the five pieces no single ranking guide combines today.
What Is Directus?
Directus is a database-first headless content platform: instead of owning your schema the way most CMSs do, it introspects the SQL database you already have (or one it creates for you) and generates a polished admin app, REST and GraphQL APIs, role-based permissions, and a no-code automation builder on top of it. The project is actively maintained — version 12.6.0 was released on October 27, 2026, and the repository holds more than 38,000 stars on GitHub (checked this week).
One license heads-up, because it changed recently: Directus now ships under the Monospace Sustainable Core License 1.0 (MSCL-1.0-GPL), a fair-code license — free to self-host and use, including in production, with the notable exclusion of "Competing Use" against Directus's own paid offerings. So do not file it mentally as plain open-source GPL; self-hosting your own instance is fully covered, running a competing hosted CMS on it is not.
Directus suits you if you already have data and want an admin UI and an API without writing either. It is a different lane from a hosted backend-as-a-service — our Supabase beginner guide covers the hosted route, where someone else runs the infrastructure; Directus is the self-hosted route, where the data lives on your own database and your own server.
How Do You Use Directus? The 10-Step First-Run Arc
Using Directus is a short arc: start it, claim the admin account, model a collection, lock down roles, then consume the API. The whole afternoon looks like this:
- Start it with persistence. Compose file with the three data volumes — never the throwaway one-liner for real data.
- Create the first admin. The onboarding screen at port 8055 walks you through it.
- Build your first collection. A collection is a database table with Directus metadata; fields define the columns.
- Add fields. Text, numbers, dropdowns, images, Markdown, dates — each field gets a display interface.
- Apply the roles-first rule. Build a restricted role and test its API read before exposing anything.
- Create items. Rows of content, entered in the admin app.
- Read them through the API. GET /items/<collection> returns JSON — that is the API lesson.
- Authenticate properly. Short-lived JWTs for apps, static tokens for server-to-server scripts.
- Automate with Flows. Event hooks and cron triggers that run operations without code.
- Back up the database behind it. Directus is a layer — your backups live at the database.
Steps 1–4 take about twenty minutes; steps 5–8 are where the security thinking happens. The sections below walk every step with the current (v12.x) commands and settings.
What Do You Need Before You Start?
You need a machine that runs Docker — a home server, a laptop, or a rented VPS — plus a browser for the admin app. A first instance is light: the SQLite default needs under a gigabyte of RAM, and port 8055 must be free on the host. If the machine is a rented server, our what is VPS hosting explainer covers what you are actually buying.
The only other requirement is a long random value for the SECRET environment variable, which signs your access tokens — set it before the first startup, never after the instance is public. Keep a terminal open: Directus is configured through environment variables and its compose file, and you will edit both today.
How Do You Install Directus with Docker?
Install Directus with a compose file that keeps your data — The official Directus Docker quickstart one-liner (docker run -p 8055:8055 directus/directus) explicitly loses everything when the container stops, because its SQLite database lives inside the container. So this Directus for beginners guide starts with the persistent version, once:
services:
directus:
image: directus/directus:latest
ports:
- 8055:8055
volumes:
- ./database:/directus/database
- ./uploads:/directus/uploads
- ./extensions:/directus/extensions
environment:
SECRET: "replace-me-with-a-long-random-secret"
DB_CLIENT: "sqlite3"
DB_FILENAME: "/directus/database/data.db"
WEBSOCKETS_ENABLED: "true"
PUBLIC_URL: "http://localhost:8055"
The three volumes are the whole persistence story: ./database holds the SQLite file, ./uploads holds every file users upload, and ./extensions holds customizations. Create the file as compose.yaml, run docker compose up -d, then open http://localhost:8055 — the onboarding screen creates your first administrator account. Pin the image tag (e.g. directus/directus:12.6.0) once you settle on a version you like; latest moves with each release.
Two staleness warnings that save real time: the environment variable KEY does not exist anymore (it was replaced by SECRET back in v9, but old tutorials still type it), and ADMIN_EMAIL/ADMIN_PASSWORD are optional bootstrap overrides — the current official sample does not use them, because the onboarding screen creates the admin.
Which Database Should Directus Use?
Start with SQLite — the compose file above uses it — and switch to a dedicated database server when the project is real. Directus supports Postgres, MySQL, MariaDB (through the mysql client), SQL Server (mssql), Oracle (oracledb), CockroachDB, and SQLite, chosen with the DB_CLIENT variable. Decide with this:
| If you... | Use... | Why |
|---|---|---|
| Are learning this afternoon | SQLite (the default) | Zero setup; one file in ./database |
| Run a real site or app | PostgreSQL | First-class backend, scales cleanly |
| Already run MySQL or MariaDB | The mysql client | Directus wraps the database you own |
| Live in an enterprise stack | oracledb or mssql | Both still supported in 2026 |
For Postgres, swap the environment block: DB_CLIENT: "pg" plus DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, and DB_DATABASE. Directus creates its own system tables inside that database on first boot and leaves your tables alone. A Directus self hosted setup is fully yours — the database, the uploads, and the backups all live where you put them.
How Do You Create Your First Collection?
Create your first collection in the admin app: Settings → Data Model → Create Collection (or the Content icon → Create Collection). Directus collections are database tables plus Directus metadata — and each collection's name is immutable after creation, so pick it like a table name: lowercase, plural, no spaces (e.g. articles).
Each collection needs a primary key. Directus offers auto-incremented integers, auto-incremented big integers (MySQL and Postgres only), generated UUIDs, or manually entered strings. Auto-incremented integers are the beginner default; generated UUIDs are the safer choice if the data will ever sync across systems. Then add fields — each field is a column plus a display interface: Input for short text, Textarea or WYSIWYG for long text, Dropdown for fixed options, Boolean for toggles, Datetime for dates, Image/File for uploads, Markdown for formatted content. Add a Validation rule (Directus supports regex validation) anywhere a wrong value would hurt later.
Do not model the whole database on day one. One collection with five fields, two test items, and a working API read teaches more than a perfect schema that never ships.
What Are Directus Roles and Permissions — and Why Do They Come First?
Directus roles and permissions are the product: every API read in Directus is filtered through a role, and all data is private by default. This guide calls the posture the roles-first rule: build a restricted role, test what it can read through the API, and only then decide what the public role may touch — never enable public read first and "tighten it later."
Directus ships with three role shapes: the public role (what unauthenticated API calls can reach — it starts with zero permissions on every collection, and you should keep it that way until you have tested), the administrator role (total control), and custom roles you create, which start with every permission off. Each user gets exactly one role. Find it all under Settings → Roles & Permissions (labeled "Access Policies" in newer docs). For each role, set CRUD permissions per collection, and field-level permissions inside the collection — you can expose a post's title publicly while hiding its internal notes field. That granularity is why the Directus roles permissions model is worth learning before your first public API call.
The roles-first rule in practice: create a "reader" role with read-only access to your articles collection, create a non-admin user on that role, and curl the API as that user before you ever touch the public role. The official video guidance and the community checklists agree on the test: confirm enforcement through the API itself, not by looking at the Studio — the Studio and the API apply the same permissions, but your visitors only ever touch the API. Say the sensitive-data check out loud: if this API token leaked tomorrow, what could it read?
How Do You Read Your Data Through the API?
Reading your data through the API is the payoff: every collection you created is instantly a REST endpoint, no code written. The patterns are uniform:
# List items (add ?filter, ?sort, ?fields, ?limit)
GET http://localhost:8055/items/articles
# One item
GET http://localhost:8055/items/articles/1
# Create / update / delete
POST http://localhost:8055/items/articles
PATCH http://localhost:8055/items/articles/1
DELETE http://localhost:8055/items/articles/1
The same data is also queryable over GraphQL: POST /graphql for your collections, /graphql/system for the system collections. That is the API lesson — model once, consume from any client.
Authentication has two shapes. Apps and people use short-lived JWTs: POST /auth/login with email and password returns an access token plus a refresh token (POST /auth/refresh rotates it) — the docs call this the most secure option. Server-to-server scripts use static tokens: set one per user, it never expires, and it is "less secure, but quite useful for server-to-server communication." Pass the token as an Authorization: Bearer header (or the access_token query param). If you prefer typed app code against your own database from scratch, our Prisma beginner guide covers that lane; Directus is the layer that turns the same database into instant APIs for everyone else.
How Do You Use the Directus SDK?
Use the official JavaScript SDK when your frontend needs typed, composable API calls instead of raw HTTP. Install it and wire the REST composable:
npm install @directus/sdk
import { createDirectus, rest, readItems } from '@directus/sdk';
const directus = createDirectus('http://localhost:8055').with(rest());
const articles = await directus.request(readItems('articles'));
The SDK v10+ API is composable: rest() for REST, graphql() for GraphQL, authentication() for login flows, realtime() for websocket subscriptions, staticToken() for server scripts. It respects the same roles you configured — an SDK call as a restricted user sees exactly what that role's permissions allow.
How Do You Point Directus at an Existing Database?
Point Directus at an existing database by giving it connection credentials — it introspects your schema and turns every table into a managed collection, with your data immediately readable through the API and the admin app. "Pointing Directus at an existing populated database is sufficient to start managing its data and serving it through an API" is the official line. This Directus existing database behavior is the headline feature — your schema stays yours, and your tables appear as managed collections the moment the connection works., and the beginner path is the Postgres swap from the database section: set DB_CLIENT: "pg" and the DB_HOST/DB_PORT/DB_USER/DB_PASSWORD/DB_DATABASE values, restart, and watch your tables appear as collections.
Directus adds its own system tables and collection metadata alongside your tables; it does not rewrite your schema. This database-first behavior is the whole differentiator against code-first CMSs, and it is also why the roles-first rule matters doubly here: your existing data was never behind an API before, so audit what the public role can reach before the instance leaves localhost.
What Can Directus Flows Automate?
Directus Flows are the no-code automation builder: triggers watch for things happening, operations do things in response. Build them in Settings → Flows. Triggers come in four flavors — Event Hook (e.g. items.create on a collection), Manual Trigger (a button in the app), Webhook (an incoming HTTP call), and CRON (a schedule). Operations include Webhook/Request URL, Create/Read/Update Data, Condition branches, and Send Email.
A classic first flow: an Event Hook on items.create for your articles collection, scoped to new drafts, chained to a Send Email operation that notifies the editor — a review queue with zero code. The official tutorials ship three ready recipes (workflows section), and the pattern generalizes: any repeatable "when this row changes, do that" job your team does by hand is a Flow candidate.
Directus vs Strapi: Which Headless CMS Fits?
Choose Directus if you have a database; choose Strapi if you want the CMS to own the schema. They are the two names every "headless cms self hosted" search compares, and the difference is one honest line each side. Directus is database-first: point it at an existing Postgres, MySQL, SQLite, SQL Server, Oracle, or CockroachDB and it wraps it with instant REST/GraphQL APIs — your schema stays yours. Strapi is code-first: you define content types in Strapi and it creates and manages its own database schema; it cannot be pointed at an existing database.
| Directus | Strapi | |
|---|---|---|
| Starting point | Your existing SQL database (introspected) | Content types you define in the CMS |
| Schema ownership | Yours — Directus adds metadata alongside | Strapi creates and manages it |
| API style | REST + GraphQL, auto-generated per collection | REST + GraphQL, generated from content types |
| License (2026) | MSCL-1.0-GPL (fair-code; competing use excluded) | Mixed license files — verify current terms yourself |
| Beginner fit | You already have data to manage | You are building the content model from zero |
Do not split this question into its own research project: if the database already exists, Directus is the answer; if nothing exists yet, either works and the schema-ownership line above decides.
How Do You Serve Directus Over HTTPS?
Serve Directus over HTTPS by putting a reverse proxy in front of port 8055 — Directus itself listens on plain HTTP behind it. The proxy terminates TLS and forwards to localhost:8055; set the PUBLIC_URL environment variable to your public domain so generated links and the admin app agree on the address. Our Caddy beginner guide walks the two-line reverse-proxy config that covers this exactly. Never expose the admin app or the API on the open internet without the roles-first pass from the permissions section — HTTPS encrypts traffic, it does not replace permissions.
What Are the Beginner Mistakes to Avoid?
The mistakes are all documented, and they all waste a weekend:
- Running the quickstart one-liner for real data. No volumes means the SQLite file dies with the container — the compose file above exists for exactly this.
- Typing KEY into the environment. Stale since v9; the variable is
SECRET, and old tutorials still show the old name. - Demo secrets on a public host.
SECRETmust be a long random value set before the first startup — never ship the placeholder. - Public read before the restricted-role test. The public role starts with zero permissions for a reason; test a real restricted user through the API first.
- Pointing at production data first. Introspect a copy, audit the roles, then connect the real database.
- Forgetting the uploads volume. Files users upload vanish with the container just like the database does.
- Treating the container as the backup. Back up the database behind Directus (plus the uploads directory) on a schedule — Directus is a layer, not a vault.
Sources
Every fact in this guide was verified on 2026-11-01 — making this Directus tutorial current as of November 1, 2026: the latest release (v12.6.0, released October 27, 2026) and the star count (~38,770 stars) at api.github.com/repos/directus/directus/releases/latest and /repos/directus/directus; the license change (MSCL-1.0-GPL, Monospace Sustainable Core License 1.0, competing use excluded) at api.github.com/repos/directus/directus/license; the Docker image (directus/directus), the latest tag update (2026-10-27), and port 8055 at hub.docker.com/v2/repositories/directus/directus/tags/latest and directus.com/docs/configuration/general; the quickstart one-liner and its verbatim no-persistence warning ("Once you stop the Docker container from running, any changes you've made will be lost") plus the official compose volumes (./database, ./uploads, ./extensions) and the current env sample (SECRET required, KEY removed, ADMIN_EMAIL/ADMIN_PASSWORD optional bootstrap overrides, DB_CLIENT sqlite3, WEBSOCKETS_ENABLED) at docs.directus.io/getting-started/quickstart.html; the supported databases (pg/postgres, mysql, oracledb, mssql, sqlite3, cockroachdb) at directus.com/docs/configuration/database; the existing-database introspection line ("Pointing Directus at an existing populated database is sufficient to start managing its data and serving it through an API") at directus.com/docs/guides/data-model/collections and betterstack.com/community/guides/linux/directus-backend; the collections model (collections as tables with metadata, immutable names, primary-key types, creation via Settings → Data Model) at directus.com/docs/guides/data-model/collections; the field interfaces (Input, Textarea, WYSIWYG, Dropdown, Boolean, Datetime, Image/File, Markdown, regex validation) at directus.com/docs/frameworks/nextjs/dynamic-forms and neon.com/guides/directus-cms; the REST patterns (/items/<collection>, /items/<collection>/<id>, filter/sort/fields/limit) and GraphQL (/graphql, /graphql/system) in the dev.to 0012303 trilogy and umatechnology.org; the auth model (temporary JWT via POST /auth/login with refresh token, static per-user tokens, Bearer header, all data private by default) at directus.com/docs/api/authentication; the roles model (public role zero permissions by default, administrator total control, custom roles start fully off, one role per user, Settings → Roles & Permissions) in the official Directus "Roles and Permissions" video and the directus.com Next.js tutorial; the roles-test guidance ("test each role with a real record", confirm enforcement through the API) at anygen.io/showcase/directus and learndirectus.com; the Flows builder (triggers: Event Hook, Manual Trigger, Webhook, CRON; operations: Webhook/Request URL, Create/Read/Update Data, Condition, Send Email) at directus.com/docs/tutorials/workflows and watch-learn.com; the SDK (npm install @directus/sdk, createDirectus().with(rest()), readItems composable, v10+ composables) at the docs.directus.io SDK reference; the Directus-vs-Strapi one-liners (database-first introspection vs code-first own-schema; Strapi cannot point at an existing database; Strapi's ~73,420 stars and NOASSERTION/mixed license files at api.github.com/repos/strapi/strapi — the "MIT" claim left unverified) from the sources above; and the field context (the three dev.to promos splitting collections/relationships/permissions, the Neon Docker+Postgres+Astro arc, the typevar.dev 2025-10-04 guide, the opensourceprojects.dev overview) from the November 1, 2026 SERP. The 10-step first-run arc, the database decision table, the Directus-vs-Strapi table, and the roles-first framing are original syntheses for this guide.
Frequently Asked Questions
Is Directus free?
Yes — Directus is free to download, run, and self-host, including in production. The 2026 license is the Monospace Sustainable Core License 1.0 (MSCL-1.0-GPL): free for internal use, non-commercial research, and professional services for licensees, with "Competing Use" against Directus's own paid offerings excluded. It is not plain open-source GPL anymore — read the license file if you plan to build a business on top of it.
What is the difference between Directus and a database GUI?
A database GUI lets you browse rows; Directus turns the database into a product surface. It adds a polished admin app for non-technical editors, role-based permissions with field-level granularity, auto-generated REST and GraphQL APIs, and a no-code automation builder — the database stays the single source of truth, but everyone from editors to apps gets a safe doorway in.
Can Directus work with my existing database?
Yes — that is its headline feature. Point Directus at an existing Postgres, MySQL, MariaDB, SQL Server, Oracle, CockroachDB, or SQLite database and it introspects your schema, exposing every table as a managed collection with an instant API. It adds its own system tables alongside yours and leaves your schema alone. Test on a copy first, and audit roles before the instance leaves localhost.
Directus vs Strapi — which should I learn?
If you already have a database, learn Directus — it wraps what you own. If you are starting from zero and want the CMS to create and manage the schema for you, Strapi fits that code-first shape. For a beginner with data in hand, Directus's database-first model means your first API exists minutes after the container starts.
How do I back up Directus?
Back up the database behind it, not Directus itself: schedule dumps of your Postgres/MySQL/SQLite database and copy the uploads directory (or its S3 equivalent) off-server. The three compose volumes (database, uploads, extensions) are what needs to survive — a container image can always be re-pulled. There is no single built-in "export everything" button, so treat the database backup as the real backup.