---
title: "Deploy Directus"
description: "Self-host Directus — instant REST and GraphQL APIs over your SQL database"
category: "CMS"
url: https://railway.com/deploy/directus-sql-api
---

# Deploy Directus

Self-host Directus — instant REST and GraphQL APIs over your SQL database

**[Deploy Directus on Railway](https://railway.com/template/directus-sql-api)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/directus-sql-api/manifest.json

- **Creator:** SB
- **Category:** CMS

## Template content

### Postgres https://devicons.railway.app/i/postgresql.svg

- **Image:** ghcr.io/railwayapp-templates/postgres-ssl:18

### Redis https://cdn.sanity.io/images/sy1jschh/production/0ce0bfdcfbdbf69662b1116671f97c2dd788b655-157x157.svg

- **Image:** redis:8.2
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### directus https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/directus.svg

- **Image:** directus/directus:latest
- **Public domain:** Yes

## Buckets

- **directus-storage**

## Documentation

# Deploy and Host Directus on Railway

Directus turns a SQL database into a REST API, a GraphQL API and an admin app, without generating code or imposing a schema. Point it at Postgres, MySQL or SQL Server and existing tables become endpoints with roles, permissions and a Studio non-technical colleagues can use. This template runs it with managed Postgres, Redis and object storage — and says what connecting a database you already own does to it.

## What This Template Deploys

| Service | Purpose |
| --- | --- |
| `directus` | API and Studio on port `8055`. Public HTTPS domain. |
| `Postgres` | Schema, content, users, roles, permissions, system tables. Volume attached. |
| `Redis` | Cache, rate limiter, and the message bus behind realtime editing. |
| `Bucket` | S3-compatible storage for uploads and Marketplace extensions. |

Everything talks over Railway's private network and only Directus takes a public domain. Files go to object storage rather than a volume, which is what lets you add replicas later without the file library splitting in two.

## About Hosting

Directus deploys cleanly. What catches people is what it writes into your database, and which features its licence tier actually enforces.

**Connecting an existing database means Directus writes into it.** The pitch is that it wraps a database you already have, and it does — but it also creates roughly twenty `directus_*` system tables inside it for its own users, roles, permissions and schema metadata. The Studio also exposes schema editing, so anyone with admin rights can alter your real tables from a web UI. Never point it at production with an owner-level account: use a dedicated schema and a scoped user, or a replica.

**The licence changed, and most guides describe the old one.** Directus 12 is under the Monospace Sustainable Core License, not the BSL 1.1 terms still quoted with a $5M revenue threshold. Self-hosted instances run the free Core tier with no key required; a `LICENSE_KEY` unlocks the licensed tier, and each release additionally becomes GPL-3.0 four years after shipping. Read the current terms, not last year's blog post.

**Some permission enforcement lives in the licensed tier.** Enforceable RBAC filters are a licensed feature, so you can build a permissions model on Core, see it in the UI, and find filters are not applied as expected. Test access rules against the API with a real token, not in the Studio.

**Railway mounts volumes as root and Directus runs unprivileged.** Use a volume and its ownership must be repaired before Directus starts, or writes fail silently. This template sends files to object storage instead, sidestepping the problem and matching what upstream documents for production.

**`KEY` and `SECRET` must never change after first boot.** They identify the project and sign sessions and tokens; rotate either and every existing session and token is invalid. Both are generated once here.

**A stock Directus deploy prints its admin password to the log.** With no `ADMIN_EMAIL` and `ADMIN_PASSWORD` set, bootstrap generates credentials and logs them, so getting in means scrolling the deploy log — and once it rotates, the password is gone. Set both as variables.

Typical cost: **~$20–35/month** for the four services at $10/GB/month RAM, $20/vCPU/month CPU and $0.15/GB/month volumes, plus storage. Directus Core is free to self-host.

## How It Compares

| | Directus | Strapi | Supabase | Hasura |
| --- | --- | --- | --- | --- |
| Works on an existing schema | Yes | No | Yes | Yes |

The honest edge: Strapi is MIT and owns its own schema, simpler if you start from nothing and never want a licence question. Hasura is faster at pure GraphQL over an existing database with no admin app to maintain. Directus wins on a combination the others do not offer together — it adapts to a schema you already have *and* gives non-technical people a usable interface onto it. Need only one of those, and something lighter will do.

## Deploy in Under 5 Minutes

1. Click **Deploy** and pick a workspace. `KEY`, `SECRET`, the database password and the admin password are generated as variables.
2. Find `ADMIN_EMAIL` and `ADMIN_PASSWORD` in the service variables, not the deploy log.
3. Open the public domain and sign in. The Studio asks you to register a project owner for licence compliance and offers a key field; dismiss both on the free Core tier.
4. Create a collection. That is a schema write, so it proves the database connection works, not just that the container is up.
5. Upload a file and confirm it lands in the bucket, then create a token under **Settings → Access Policies** and query `/items/` with it.

> Verify before you rely on it: redeploy, sign in with the same credentials, and re-query that collection through the API. Working means `KEY`, `SECRET` and storage all survived; a 401 means something rotated that should not have.

## Common Use Cases

- **An API over a database you already run** — expose existing tables as REST and GraphQL with no backend to write, on a scoped user and a dedicated schema.
- **Headless CMS for a front end** — pages, posts and media served to Next.js, Astro or Nuxt, editors working in the Studio.
- **Internal admin panel** — a real interface onto application data, with roles controlling who sees what.

## Configuration

| Variable | Required | Description |
| --- | --- | --- |
| `KEY` | Generated | Unique project identifier. Never change after first boot. |
| `SECRET` | Generated | Signs sessions and tokens. Changing it invalidates every session. |
| `DB_CLIENT`, `DB_*` | Auto | `pg` plus reference variables on the private Postgres host. |
| `PUBLIC_URL` | Required | Public HTTPS domain. Asset URLs and OAuth redirects are built from it. |
| `ADMIN_EMAIL`, `ADMIN_PASSWORD` | Required | First administrator. Without these, credentials are generated into the log. |
| `STORAGE_S3_*` | Auto | Object storage for uploads and extensions. |

> **Never rotate `KEY` or `SECRET` on a live instance.** They identify the project and sign every token, so changing either logs everyone out and invalidates issued API tokens.

> **Connect external databases with a scoped user.** Directus creates its own system tables in whatever it connects to and exposes schema editing in the Studio. An owner-level account on a production database is a bad afternoon waiting to happen.

## Dependencies for Directus Hosting

- **Railway account** — ~$20–35/month for Directus, Postgres and Redis, plus storage.
- **Bundled services** — Postgres for schema and content, Redis for cache and realtime, an S3-compatible bucket for files and extensions.
- **Volume** — on Postgres. Directus stays stateless because uploads go to object storage.
- **Optional** — a `LICENSE_KEY` for the licensed tier, SMTP for password resets, PostGIS for spatial types.

### Deployment Dependencies

- [Directus on GitHub](https://github.com/directus/directus)
- [Directus documentation](https://directus.io/docs)
- [Directus environment variables](https://directus.io/docs/configuration/general)
- [Railway private networking](https://docs.railway.com/networking)

### Implementation Details

Directus runs the official image on a pinned tag rather than `latest`, serving `8055` behind Railway's HTTPS edge. Postgres and Redis are reached by private hostname through reference variables, and files go to an S3-compatible bucket rather than a volume. That choice matters more than it looks: Railway mounts volumes as root while the Directus image runs unprivileged, so a volume-backed file library needs ownership repaired before startup or writes fail quietly.

The database relationship is worth understanding before you connect anything you care about. Directus introspects your schema to build collections, but also writes its own system tables — users, roles, permissions, presets, schema metadata — into the same database. It is a tenant of that database, not a reader. Give it a dedicated schema and a scoped user, and keep the Studio's schema editing in mind when deciding who gets an administrator role.

For backups, Postgres holds your content and Directus's own configuration, so a `pg_dump` captures collections, roles and permissions together. Back up the bucket alongside it: the database stores file metadata while the bytes live in object storage, and restoring one without the other leaves a library full of broken references. Store `KEY` and `SECRET` with the dump.

## Frequently Asked Questions

**Can I point Directus at my production database?** You can, but it writes about twenty system tables into it and exposes schema editing in the Studio. Use a dedicated schema with a scoped user, or a replica.

**Is Directus free to self-host?** The Core tier is, with no licence key. Directus 12 is under the MSCL rather than the older BSL 1.1 terms, and each release additionally becomes GPL-3.0 four years after shipping.

**Why aren't my permission filters enforced?** Enforceable RBAC filters are a licensed-tier feature. Test access rules against the API with a real token rather than trusting the Studio preview.

**Where is my admin password?** In the service variables, because this template sets them explicitly. A stock deploy generates them into the log instead.

**Do uploads survive a redeploy?** Yes — files go to object storage, not a container filesystem, which also lets you add replicas later.

## Why Deploy Directus on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Directus on Railway you get the production shape upstream documents — Postgres and Redis on the private network, files and extensions in object storage rather than a root-owned volume, `KEY` and `SECRET` generated once and held stable, and an admin credential you can read in your service settings rather than a log.

## Similar templates

- [Libredesk - Complete Setup](https://railway.com/deploy/libredesk-complete-setup) — Complete self-hosted omnichannel customer support desk.
- [Paperless-ngx](https://railway.com/deploy/paperless-ngx-3) — Paperless-ngx — document management with OCR and full-text search
- [Instatic CMS - Postgres](https://railway.com/deploy/instatic-cms-postgres) — Design, build and manage powerful static sites from state-of-the-art CMS

Open this page in a browser: https://railway.com/deploy/directus-sql-api
