Content Modeling
Application patterns for reusable sections, relationships between records, and content structures that can grow with a project.
Use these patterns when the main question is how to shape the content itself. They help you decide how records relate to each other, how flexible a page should be, and how to avoid locking editors into brittle one-off structures.
Build flexible pages from reusable blocks
Problem: you want editors to build or rearrange page sections without turning each page into one giant object.
This pattern uses blocks to model page sections as reusable building blocks inside a page layout. It is the right starting point when you need flexible landing pages, marketing pages, or reusable content sections.
Example implementation
import { defineBlock, defineBlocksField, defineCollection, defineTextField, defineTextareaField, defineUrlField } from "@dyrected/core";
export const HeroBlock = defineBlock({
slug: "hero",
labels: { singular: "Hero", plural: "Heroes" },
fields: [
defineTextField({ name: "heading", label: "Heading", required: true }),
defineTextareaField({ name: "body", label: "Body" }),
],
});
export const CallToActionBlock = defineBlock({
slug: "callToAction",
labels: { singular: "Call to action", plural: "Calls to action" },
fields: [
defineTextField({ name: "label", label: "Link label", required: true }),
defineUrlField({ name: "url", label: "URL", required: true }),
],
});
export const Pages = defineCollection({
slug: "pages",
fields: [
defineTextField({ name: "title", label: "Title", required: true }),
defineBlocksField({
name: "layout",
label: "Page layout",
blocks: [HeroBlock, CallToActionBlock],
}),
],
});
Read the full docs:
Model a relationship and its reverse lookup
Problem: one record should point to another record, and you also want the reverse view without storing duplicate data.
This pattern stores the owning relationship on one side and uses a join field for the reverse lookup. It is a good fit for authors and posts, products and categories, or any one-to-many content structure.
Example implementation
import { defineCollection, defineJoinField, defineRelationshipField, defineTextField } from "@dyrected/core";
export const Users = defineCollection({
slug: "users",
auth: true,
fields: [
defineTextField({ name: "name", label: "Name", required: true }),
defineJoinField({
name: "posts",
label: "Posts",
collection: "posts",
on: "author",
limit: 20,
}),
],
});
export const Posts = defineCollection({
slug: "posts",
fields: [
defineTextField({ name: "title", label: "Title", required: true }),
defineRelationshipField({
name: "author",
label: "Author",
relationTo: "users",
required: true,
}),
],
});
Read the full docs:
Create a site settings global
Problem: you need one shared place for site name, support details, and other values that should only exist once.
This pattern uses a global for singleton content instead of forcing editors to manage a one-row collection. It fits site settings, contact information, default CTA copy, and other values reused across many frontend surfaces.
Example implementation
import { defineEmailField, defineGlobal, defineTextField, defineUrlField } from "@dyrected/core";
export const SiteSettings = defineGlobal({
slug: "site-settings",
label: "Site settings",
initialData: {
siteName: "Acme Studio",
supportEmail: "[email protected]",
},
fields: [
defineTextField({ name: "siteName", label: "Site name", required: true }),
defineTextField({ name: "tagline", label: "Tagline", defaultValue: "" }),
defineEmailField({
name: "supportEmail",
label: "Support email",
required: true,
}),
defineUrlField({
name: "primaryCta",
label: "Primary call to action",
}),
],
});
Read the full docs:
Create a navigation global with nested links
Problem: editors need to manage shared navigation without hardcoding menus in the frontend.
This pattern models navigation as repeatable rows in a global, with one level of child links for grouped menus or dropdowns. It is a practical default for headers, footers, and docs navigation that should stay structured.
Example implementation
import { defineArrayField, defineGlobal, defineTextField, defineUrlField } from "@dyrected/core";
export const Navigation = defineGlobal({
slug: "navigation",
label: "Navigation",
fields: [
defineArrayField({
name: "items",
label: "Navigation items",
fields: [
defineTextField({ name: "label", label: "Label", required: true }),
defineUrlField({ name: "link", label: "Link", required: true }),
defineArrayField({
name: "children",
label: "Child links",
fields: [
defineTextField({ name: "label", label: "Label", required: true }),
defineUrlField({ name: "link", label: "Link", required: true }),
],
}),
],
}),
],
});
Read the full docs:
Create a category taxonomy for content
Problem: entries need reusable categories so editors can organize content and build filtered listing pages.
This pattern stores categories in their own collection and relates content back to them with a has-many relationship field. It is a good fit for blogs, resources, case studies, and any content type that benefits from reusable taxonomy entries.
Example implementation
import { defineCollection, defineRelationshipField, defineTextField } from "@dyrected/core";
export const Categories = defineCollection({
slug: "categories",
admin: { useAsTitle: "title", urlPattern: "/categories/{slug}" },
fields: [
defineTextField({ name: "title", label: "Title", required: true }),
defineTextField({ name: "slug", label: "Slug", required: true, unique: true }),
],
});
export const Posts = defineCollection({
slug: "posts",
admin: { useAsTitle: "title", urlPattern: "/blog/{slug}" },
fields: [
defineTextField({ name: "title", label: "Title", required: true }),
defineTextField({ name: "slug", label: "Slug", required: true, unique: true }),
defineRelationshipField({
name: "categories",
label: "Categories",
relationTo: "categories",
hasMany: true,
}),
],
});
Read the full docs:
Application Patterns
Browse Dyrected application patterns by problem, get a short summary of what each one solves, and jump straight to the canonical docs when you need the full explanation.
Access Control
Application patterns for row-level access, role-based permissions, and deciding who can operate on which content.