The fastest way to a CMS everyone hates is to model your content after your components. It feels efficient — a HeroWithTwoColumnsAndCta document type maps perfectly onto the React component of the same name. Then the design changes and the content is worthless.
Model meaning, not layout
The question to ask about every field is: *is this a fact about the thing, or a decision about how it looks today?*
A case study has a client, a year, a role, an outcome. Those are facts. It does not have a headingColour or a imageOnTheLeft boolean — those are presentation, and presentation belongs in code where it can be changed without a migration.
This is also the difference between content you can syndicate and content you can't. Facts can be rendered as a card, a list row, an OG image, an RSS item, or a search result. Layout decisions can only be rendered as themselves.
Let editors compose, within limits
The counter-argument is real: editors need flexibility, and a rigid schema pushes them to abuse a rich text field until it becomes a layout engine.
The middle ground that has worked for me is a small, closed set of composable blocks. Not "any component anywhere" — a curated list, each of which is a meaningful content unit rather than a layout primitive. A "quote with attribution" block, yes. A "two column container" block, no.
Validate at the edge
Schema validation in the CMS is where content quality actually gets enforced, and it's consistently under-used. Required alt text. A maximum length on anything that appears in a card, so the design can't be broken by a 200-character title. A regex on slugs.
Every one of those rules is a bug that can now never reach production, caught by the person best placed to fix it.
Query for the shape the component needs
The last piece is not letting CMS shapes leak into components. A projection that returns exactly the fields a card needs — flattened, with images already resolved to URLs — means the component has no idea which CMS it's talking to.
That indirection sounds like ceremony until you migrate. Then it's the only reason the migration is a few files rather than a rewrite.