Collections & Globals
The two building blocks of a Dyrected content model — when to use each and what they give you.
Every Dyrected project is made of two primitives: collections and globals. Together they define your content model, your database schema, your REST API, and your Admin UI — all from one config file.
Collections
A collection is for content that has more than one instance — blog posts, products, users, orders, form submissions. Each entry is a separate document with its own id.
export const Posts = defineCollection({
slug: 'posts',
fields: [
{ name: 'title', label: 'Title', type: 'text', required: true },
{ name: 'status', label: 'Status', type: 'select', options: ['draft', 'published'] },
],
})Defining a collection gives you, automatically:
| What you get | Detail |
|---|---|
| List endpoint | GET /api/collections/posts — paginated, filterable, sortable |
| Single endpoint | GET /api/collections/posts/:id |
| Create endpoint | POST /api/collections/posts |
| Update endpoint | PATCH /api/collections/posts/:id |
| Delete endpoint | DELETE /api/collections/posts/:id |
| List page in Admin UI | Searchable table with configurable columns |
| Edit page in Admin UI | Form generated from your fields array |
| SDK methods | .collection('posts').find(), .findOne(), .create(), .update(), .delete() |
Globals
A global is for content that has exactly one instance — site settings, a navigation menu, a homepage hero, legal copy. There is no list; there is only one document, and it is always there.
export const SiteSettings = defineGlobal({
slug: 'site-settings',
fields: [
{ name: 'siteName', label: 'Site Name', type: 'text' },
{ name: 'logoUrl', label: 'Logo Url', type: 'url' },
{ name: 'primaryColor', label: 'Primary Color', type: 'text' },
],
})Defining a global gives you:
| What you get | Detail |
|---|---|
| Get endpoint | GET /api/globals/site-settings |
| Update endpoint | PATCH /api/globals/site-settings |
| Edit page in Admin UI | Single form — no list, no create button |
| SDK method | .global('site-settings').get(), .update() |
The decision rule
Does this content have more than one instance? — Yes → Collection — No → Global
When in doubt, apply it literally:
| Content | Type | Why |
|---|---|---|
| Blog posts | Collection | Many posts |
| Products | Collection | Many products |
| Users / members | Collection | Many users |
| Orders | Collection | Many orders |
| Contact form submissions | Collection | Many submissions |
| Site settings | Global | One set of settings |
| Navigation menu | Global | One nav |
| Homepage hero | Global | One hero section |
| Cookie policy text | Global | One document |
| SEO defaults | Global | One set of defaults |
If you think you need two globals for the same concept (e.g. "desktop nav" and "mobile nav"), that is usually a sign the nav structure should be a field on a single global, not two globals.
Both live in defineConfig
// dyrected.config.ts
import { defineConfig } from '@dyrected/core'
export default defineConfig({
db: adapter,
collections: [Posts, Products, Users],
globals: [SiteSettings, Navigation],
})The order of entries in each array controls the order they appear in the Admin UI sidebar.
What the slug controls
The slug is the identifier used everywhere — in API paths, SDK calls, and the Admin UI URL. It must be unique across all collections and globals, lowercase, and hyphenated.
// slug: 'site-settings'
// → API: GET /api/globals/site-settings
// → SDK: cms.global('site-settings').get()
// → Admin: /admin/globals/site-settingsNext steps
- Fields — define the shape of each collection or global
- Access Control — control who can read or write each collection
- Schema Definition — how collections map to your database and how migrations work
- Globals & Site Settings guide — a practical walkthrough