Platform · Content modeling

One model for linked entries and nested components?

Uniwoven has one type system with two kinds of content type. A document is an entry of its own, and other entries link to it by reference. A component lives inside the entry that uses it and can hold other components, to any depth. One article can link its author as a document and carry its hero and FAQ as components.

Book a walkthrough →Uniwoven comes with Sonklar's team, not as a standalone licence.

One article, modelled both ways

article  "Why we hand-build frames"      document, at /journal/hand-built
├─ author ──▶ person                      document, linked by reference
├─ hero                                   component, stored inline
│   └─ cta ──▶ page                       component holding a reference
├─ body (rich text)
│   └─ embed ──▶ note "Frame warranty"    document, tracked as a link
└─ faq                                    component
    └─ items: faqItem × 3                 list of components

The person and the note have entries of their own and can be linked from any page. The hero and FAQ belong to this article and nothing else.

How it works

Documents and components, one set of rules

Both kinds share field types, validation and localisation. What differs is where the data lives.

▢

Documents are addressable.

A document has its own entry and status, and a page also has its place in the page tree. Reference fields store its ID and can be limited to certain types.

▣

Components nest to any depth.

A component is stored inside its parent and can contain components, including its own type. Click it on the page and the inspector shows only its fields.

Rich text has its own format.

We define the stored format, and the editor widget converts to it. Swapping the widget never touches stored documents. Embeds inside rich text are tracked as links, like any other reference.

⇄

Model changes never rewrite content.

Delete a field and its data stays in storage, unserved. Changing a field's type is blocked in the modelling screen and goes through a branched environment instead.

✎

Every entry can carry a brief.

The brief says what the page is for, before anyone writes. The assistant writes from it, and the site never receives it.

Components from your code

Write the schema once, in your frontend

Component types don't have to be modelled in the CMS at all. Write one zod schema per component in your frontend, and the CMS derives the content type from it. That type is read-only in the modelling screen, so nobody edits it in two places. A compatible schema change, such as a new optional field, goes straight in. A breaking one opens a drift report listing the entries it affects.

zod v4props from z.inferderived content typeread-only in the CMSdrift report
hero.tsx, and the content type the CMS derives from it
// components/contract/hero.tsx
export const heroSchema = z.object({
  heading: z.string().min(1).max(80),
  tagline: z.string().min(1).max(200).meta({ cms: 'multiline' }),
  variant: z.enum(['full', 'split']).meta({
    guidance: 'full for landing pages, split when the image matters',
  }),
  image: assetRef('image').optional(),
  cta: ctaSchema.optional(),
})
export type HeroProps = z.infer<typeof heroSchema>

// Derived: the hero component type, from the manifest (abridged)
{
  "apiId": "hero",
  "fields": [
    { "apiId": "heading", "type": "text", "required": true, "minLength": 1, "maxLength": 80 },
    { "apiId": "tagline", "type": "longText", "required": true, "minLength": 1, "maxLength": 200 },
    { "apiId": "variant", "type": "text", "required": true, "allowedValues": ["full", "split"] },
    { "apiId": "image", "type": "asset", "accept": ["image"] },
    { "apiId": "cta", "type": "component", "allowedTypes": ["cta"] }
  ],
  "guidance": { "fields": { "variant": "full for landing pages, split when the image matters" } }
}
Simplified from the hero in our sample frontend. .optional() decides required, .meta() carries hints for editors and agents, and a nested schema becomes a component field.
Our view, October 2026

Where other headless CMSes draw the line

01

Contentful links well and nests through references.

Entries link cleanly. A component, though, is an entry of its own that the page references, so a deep page becomes a chain of entries and dialogs. Uniwoven stores page-only components inline.

02

Storyblok nests well and links more loosely.

Blocks nest inside a story, and the editor is good at it. Linking one story to another goes through link and reference fields resolved per request. Uniwoven treats references as first-class and tracks every one. Contentful and Storyblok as of October 2026, from public documentation and our project experience. Corrections welcome.

Limits worth knowing

An entry publishes all its locales at once; per-locale publishing and locale fallback chains are Delivered in your rollout. The delivery API filters references by ID, not by fields inside the referenced entry. A field rename is a delete plus an add, and the modelling screen warns you. If your model needs more than this, a Setup Review tells you before you commit to anything.

See the Setup Review: €3,900 →
Questions

What content architects ask us

Yes. Documents link to each other by reference, and components live inside the entry that uses them, nested to any depth. Both kinds share one type system, with the same field types and validation, so each piece is modelled where it belongs rather than where the CMS prefers it.

Related

Where the model shows up next

Component contract

Define components in your code

Write each component's schema once, in your frontend. The content type is derived from it.

Component contract →
Environments

Change the model on a copy

Type changes and remodels run on a full copy, swapped in by alias.

Environments and export →
Decision

Keep, fix or replace your CMS?

Check whether this model is worth keeping before you move anything.

Keep, fix or replace →

See your content model in Uniwoven

A free walkthrough. We shape the sample space like your site, with your page types modelled both ways, and show you around. There's nothing to prepare.

Book a walkthrough →