Skip to main content

schema-design

Schema design best practices — data modeling, collection planning, system fields, display templates, singletons, folders, versioning. This skill should be used when the user asks to design a data model, plan collections, create a database schema, or build a CMS/e-commerce/project database structure in Directus.

Source facts

Repository
Agents-Store/codex-plugins
Last source activity
November 1, 2026 at 02:46
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
schema-design
description
Schema design best practices — data modeling, collection planning, system fields, display templates, singletons, folders, versioning. This skill should be used when the user asks to design a data model, plan collections, create a database schema, or build a CMS/e-commerce/project database structure in Directus.
# Schema Design Best practices for designing Directus data models using the `collections`, `fields`, and `schema` MCP tools. ## Design Approach 1. **Explore first** — Use `schema` tool (discovery mode) to see existing collections 2. **Plan on paper** — List entities, fields, and relationships before building 3. **Build in order** — Follow the creation order below strictly 4. **Verify** — Use `schema` tool (detailed mode) to confirm structure ## Creation Order (Critical) Build schema in this exact order to avoid dependency errors: 1. **Collection folders** — UI-only grouping (optional) 2. **Independent collections** — No foreign key dependencies (categories, tags, statuses) 3. **Dependent collections** — Main entities that reference other collections (posts, products) 4. **Junction collections** — For M2M relationships (posts_tags, product_categories) 5. **Basic fields** — Non-relational fields (string, text, integer, boolean, etc.) 6. **Relational fields** — M2O uuid fields, O2M/M2M alias fields 7. **Relations** — Define relationships after both collections and fields exist 8. **Sample data** — Create test items to verify schema ## Creating a Collection ```text Tool: collections Input: { "action": "create", "data": [{ "collection": "articles", "schema": {}, "meta": { "icon": "article", "note": "Blog articles collection", "color": "#2196F3", "sort_field": "sort", "archive_field": "status", "archive_value": "archived", "unarchive_value": "draft", "display_template": "{{title}}", "accountability": "all" } }] } ``` ### Schema Rules - `"schema": {}` — real database table - `"schema": null` — folder-only (no table, just UI grouping) ### Collection Folders Group collections in the sidebar: ```json { "action": "create", "data": [{ "collection": "content", "schema": null, "meta": { "icon": "folder", "note": "Content-related collections", "color": "#4CAF50" } }] } ``` Then assign collections to the folder: ```text Tool: collections Input: { "action": "update", "data": [{ "collection": "articles", "meta": { "group": "content" } }] } ``` ## System Fields Add these recommended fields to every content collection: | Field | Type | Purpose | |-------|------|---------| | `id` | `uuid` | Primary key (auto-generated on collection create) | | `status` | `string` | Workflow status (draft/published/archived). Directus 12 new collections get a boolean `archived` field instead, see Archive Pattern | | `sort` | `integer` | Manual sort order | | `user_created` | `uuid` | Auto-tracked creator (system field) | | `user_updated` | `uuid` | Auto-tracked last editor (system field) | | `date_created` | `timestamp` | Auto-tracked creation date (system field) | | `date_updated` | `timestamp` | Auto-tracked update date (system field) | ### Adding System Fields ```text Tool: fields Input: { "action": "create", "collection": "articles", "data": [ { "field": "status", "type": "string", "meta": { "interface": "select-dropdown", "options": { "choices": [ { "text": "Draft", "value": "draft" }, { "text": "Published", "value": "published" }, { "text": "Archived", "value": "archived" } ] }, "display": "labels", "width": "half" }, "schema": { "default_value": "draft", "is_nullable": false } }, { "field": "sort", "type": "integer", "meta": { "interface": "input", "hidden": true } }, { "field": "user_created", "type": "uuid", "meta": { "special": ["user-created"], "interface": "select-dropdown-m2o", "display": "user", "readonly": true, "hidden": true, "width": "half" } }, { "field": "date_created", "type": "timestamp", "meta": { "special": ["date-created"], "interface": "datetime", "display": "datetime", "readonly": true, "hidden": true, "width": "half" } }, { "field": "user_updated", "type": "uuid", "meta": { "special": ["user-updated"], "interface": "select-dropdown-m2o", "display": "user", "readonly": true, "hidden": true, "width": "half" } }, { "field": "date_updated", "type": "timestamp", "meta": { "special": ["date-updated"], "interface": "datetime", "display": "datetime", "readonly": true, "hidden": true, "width": "half" } } ] } ``` ## Singleton Collections For global settings, site config, or any single-record collection: ```json { "action": "create", "data": [{ "collection": "site_settings", "schema": {}, "meta": { "singleton": true, "icon": "settings", "note": "Global site configuration" } }] } ``` Singletons show as a single form (no list view) in the Directus app. ## Content Versioning Enable version tracking for editorial workflows: ```text Tool: collections Input: { "action": "update", "data": [{ "collection": "articles", "meta": { "versioning": true } }] } ``` Allows creating content versions (drafts) before publishing changes. This is the draft/publish workflow of Directus 12, and it replaces a hand-made `status` field for review flows: - The published item is addressed by the reserved version key `published` (the older `main` still works). `draft` is a reserved global version that exists for every item once versioning is on. `published`, `main` and `draft` cannot be used as custom version keys - In the Studio the published view is read-only: editing opens the draft, and Publish (with a comparison step) makes a version the published item. Creating an item in a versioned collection opens an item-less draft, publishing it creates the item and needs `create` permission - Read a version with `?version=<key>` (REST, SDK `version` option, MCP `items` query `version`). Relational data of a version must be requested with explicit field expansion. A version key that does not exist answers 403 - REST: `/versions`, `POST /versions/{id}/save`, `GET /versions/{id}/compare`, `POST /versions/{id}/promote`. SDK: `createContentVersion`, `saveToContentVersion`, `compareContentVersion`, `promoteContentVersion` - Editors need permissions beyond the collection itself: Read, Create, Update, Delete on `directus_versions` (all fields, no item rules) and Read on `directus_revisions`. Without them the Studio shows a disabled Create button, a read-only form or a Forbidden error when publishing ## Display Templates Control how items appear in relation dropdowns and lists: ```jsonc "meta": { "display_template": "{{title}} — {{author.first_name}} {{author.last_name}}" } ``` Supports field references with `{{field_name}}` and relation traversal with dot notation. ## Archive Pattern Soft-delete pattern using archive fields: ```jsonc "meta": { "archive_field": "status", "archive_value": "archived", "unarchive_value": "draft", "archive_app_filter": true } ``` When `archive_app_filter: true`, archived items are hidden by default in the app. Archived items are still returned by the API unless you filter them out. **Directus 12:** collections created through the Studio wizard get an optional boolean `archived` field (archive value `true`, unarchive value `false`) instead of a string `status`. Existing collections with a string `status` keep working with no migration. For a new collection, prefer: ```jsonc "meta": { "archive_field": "archived", "archive_value": "true", "unarchive_value": "false", "archive_app_filter": true } ``` and keep draft/review/publish in content versioning rather than in a `status` value. ## Common Design Patterns ### Blog CMS | Collection | Key Fields | Relations | |-----------|------------|-----------| | `authors` | name, bio, avatar, email | — | | `categories` | name, slug, description | — | | `tags` | name, slug | — | | `posts` | title, slug, content, excerpt, featured_image, status | M2O → authors, M2M ↔ categories, M2M ↔ tags | | `posts_categories` | (junction) | M2O → posts, M2O → categories | | `posts_tags` | (junction) | M2O → posts, M2O → tags | ### E-Commerce | Collection | Key Fields | Relations | |-----------|------------|-----------| | `brands` | name, logo, description | — | | `categories` | name, slug, parent | Self-referencing M2O | | `products` | name, sku, price, description, status | M2O → brands, M2M ↔ categories | | `variants` | sku, price, stock, attributes | M2O → products | | `orders` | number, total, status, customer_email | — | | `order_items` | quantity, price | M2O → orders, M2O → variants | ### Project Management | Collection | Key Fields | Relations | |-----------|------------|-----------| | `projects` | name, description, status, deadline | — | | `tasks` | title, description, priority, status, due_date | M2O → projects, M2O → directus_users (assignee) | | `comments` | text, date | M2O → tasks, M2O → directus_users | | `labels` | name, color | — | | `tasks_labels` | (junction) | M2O → tasks, M2O → labels | ## Primary Key Guidance - **UUID** (recommended) — Generated automatically, globally unique, best for distributed systems - **Auto-increment integer** — Simpler, readable IDs, but less portable Directus creates a UUID `id` field by default when you create a collection. ## Common Mistakes 1. **Creating relations before collections exist** — Both collections must exist first 2. **Wrong creation order** — Independent collections first, then dependent, then junction 3. **Everything in one collection** — Normalize data; use relations instead of JSON fields for structured data 4. **Missing system fields** — Always add status, user_created, date_created for content collections 5. **No display templates** — Set `display_template` so items are recognizable in relation dropdowns 6. **Forgetting archive pattern** — Use archive fields for soft-delete instead of actual deletion 7. **Not using collection folders** — Organize collections in folders for large projects
View on GitHub