Directus is only as good as the data model you give it. The tool is flexible enough to let you build almost anything, including a model that fights you for the life of the project. These are the five mistakes we see most, and what to do instead.
1. One giant "pages" collection
The tempting first move: a pages collection with title, slug, and a big
content field, and every page (home, about, pricing, a landing page, a legal
page) is a row in it.
It falls apart because those pages aren't the same thing. The homepage has a
hero, featured products, and testimonials. A legal page is a title and body. A
landing page has its own structure again. Cramming them into one collection means
either a content field so loose that nothing is reusable, or a pile of
mostly-empty optional fields.
Instead: model page types as their own collections when their structure
differs materially (landing_pages, legal_pages), and use a block-based body
(next point) for the ones that are genuinely freeform. A shared slug and
seo structure can live in a reusable field group.
2. Rich text where structured fields belong
A rich-text (WYSIWYG) field is a trap for anything that isn't prose. Product specs, feature lists, pricing tiers, team members: put them in rich text and you've turned queryable data into a blob of HTML that renders one way and one way only.
Instead: if the thing has fields, give it fields. A features collection
with title, description, icon, and sort. A pricing_tiers collection
with real columns. For editorial bodies, use Directus's many-to-any (M2A)
builder: the body is an ordered list of typed blocks (rich_text, image,
quote, code, cta), each a small collection of its own. You get content that
renders consistently on the web, in an app, and in an email, all from one source.
3. No line between content and configuration
Site settings (the header navigation, footer links, social URLs, the
announcement bar) often end up scattered: some in a globals collection, some
hard-coded, some as fields on unrelated rows.
Instead: decide deliberately. A single site_settings singleton for global
configuration. Navigation as its own collection with a self-relation for nesting,
so editors reorder it without a deploy. The rule: if a non-developer should be
able to change it, it's content and it belongs in a collection with a sensible
interface.
4. Missing draft / publish state
Directus gives you a status field pattern for free, and it's easy to skip it
early, when everything is just "live". Then someone needs to prepare next week's
launch content, or fix a typo without publishing an unrelated half-finished
edit, and there's no way to.
Instead: add status (draft / published / archived) to every
editable collection from the start, and set API permissions so the public role
only reads published. Pair it with a preview URL so editors see the real page
with their draft before it goes live. Retrofitting this once there's a live
front end depending on the old permissions is fiddly.
// public role: read permission on `articles`
{
"status": { "_eq": "published" }
}Modelling a Directus project?
We do content-model reviews: a couple of hours on your schema before it's set in stone usually saves weeks later.
Book a review →5. Relationships modelled as loose text
A category field that's just a string. An author field where someone types
the name. It works until you have "Engineering", "engineering", and "Eng" as
three categories, or an author whose bio you now want to show on every post and
can't, because there's no author record to attach it to.
Instead: if two things relate, model the relationship. articles →
many-to-one → categories. articles → many-to-many → authors. It costs a
few minutes up front and it's a painful migration later: you have to
de-duplicate the free text, create the records, and re-link every row.
The through-line
Every one of these is cheap to get right on day one and expensive to fix once there's content and a front end depending on the model. The fix is the same in each case: spend the early time on the model, with the people who'll edit the content, before building anything on top of it. That's the first phase of every Directus project we run, and it's the one that makes the rest go smoothly.