15 things every Contentful enterprise project gets wrong in the first 6 weeks
Six weeks into every Contentful enterprise build I've audited, the same 15 things are missing. None of them are exciting. All of them are blocking. This is the checklist you wish your last vendor had read.
How to use this checklist
Linking & navigation (the silent breakers)
Three of the most expensive bugs in any Contentful enterprise build are not bugs at all — they are missing primitives. They look like content problems for the first six weeks, then surface as 404 storms in week seven.
- 1. No dynamic link references. Editors paste hard-coded URLs into rich text and CTAs. Refactor a slug, and every link to it silently breaks. Production answer: a
Linkcontent type that references the target entry, not a string. Solved in the starter with a typedlinkReferenceresolver across every block. - 2. No page hierarchy. Pages live in a flat list. There is no parent/child relation, no breadcrumb derivation, no way to ask "what's under /products?". Production answer: a self-referential
parentfield on the page content type, with depth-bounded traversal. Solved in the starter via a singlegetPageTree(locale)call wired into nav and breadcrumbs. - 3. No CMS-driven navigation. Header, footer, mega-menu — all hardcoded into components. Marketing wants to add a top-level item; engineering ships a release. Production answer:
navigationMenu/navigationGroup/navigationItemcontent types with optional mega-menu media. Solved in the starter — restructure the entire site nav from Contentful, no deploy.
Internationalization (the assumption that always breaks)
Every Contentful project starts with one locale and "we'll add more later". Later is always a six-week sprint, because the foundation has to land before any real content can be translated.
- 4. No locale fallback chain. A Danish entry with no Danish copy returns null instead of falling back to English. The page renders empty. Production answer: a fallback chain baked into every CMS query, with the fallback declared per-locale in code, not per-field by editors. Solved in the starter — every
cmsFetchapplies the chain transparently. - 5. No localized slugs. URLs stay English in every market. SEO suffers in Denmark, France, and Germany — exact-match local-language slugs are a measurable ranking signal. Production answer: localized parent and child slug fields, joined per-locale at build. Solved in the starter with a localized URL builder shared by sitemap, hreflang, and the language switcher.
- 6. No CMS-driven dictionaries. UI strings ("Read more", "Submit", "Cookies") live in JSON files. Marketing wants to A/B-test "Get a quote" vs "Request pricing"; engineering ships a release. Production answer: a
localizedDictionarycontent type with{token}interpolation. Solved in the starter — every UI string is editable in Contentful.
SEO & redirects (the search-traffic killers)
The SEO checklist is not exciting. It is also non-negotiable. Every gap here costs measurable organic traffic, and most are invisible until a Search Console regression report lands six months in.
- 7. No redirect engine. Every URL change is an engineering ticket. Marketing waits a sprint to retire a campaign URL; SEO bleeds in the meantime. Production answer: a
redirectcontent type with regex/wildcard support, evaluated at the proxy edge. Solved in the starter — editors ship a redirect in 30 seconds, no deploy. - 8. No auto slug-change redirects. Editor renames a page; the old URL dies silently. Production answer: a webhook on entry update that diffs the slug field and writes a redirect entry automatically. Solved in the starter — slug refactors are safe by default.
- 9. No JSON-LD, hreflang, or llms.txt. Rich results get skipped, locale alternates get ignored, AI crawlers get nothing. Production answer: per-page JSON-LD, locale-aware
generateMetadatawith hreflang, and a/llms.txtroute with an AI crawler policy. Solved in the starter — discoverability across Google, Bing, and the LLM crawlers comes pre-wired.
Editor experience & cache discipline (the trust killers)
Editors don't read your README. They click around for thirty seconds, hit something that surprises them, and decide the CMS is broken. Three things consistently break that thirty seconds.
- 10. No Live Preview. Editors save, switch tab, hard-refresh, swear. Production answer: Contentful Live Preview wired end-to-end with the
preview-modetoken, draft fetch, and inspector overlays on every block. Solved in the starter — preview is on day one, not month four. - 11. No tag-based ISR invalidation. A content change either does nothing or nukes the entire CDN. Production answer:
revalidateTagon a per-entry-type tag, dispatched from a Contentful webhook. Solved in the starter — the webhook is registered automatically onpnpm setup. - 12. No schema-driven forms. Forms are hardcoded into components. Marketing campaigns wait on engineering. Production answer: a
formcontent type with a typed field schema and a single renderer. Solved in the starter — editors ship a new lead-capture form in an hour, not a sprint.
Type safety, security & DX (the long-tail liability)
These three don't break in week six. They break in month nine, when a junior engineer ships a regression nobody catches because the contract was implicit. By then the surface area is too large to retrofit cheaply.
- 13. No type-safe content models. Stringly-typed CMS access, runtime errors on field renames, zero compile-time safety. Production answer:
graphql-codegenagainst the live CDA schema, regenerated on everypnpm setuprun, with a drift detector that fails CI when types and CMS diverge. Solved in the starter. - 14. No hardened CSP. A default Next.js CSP allows everything; security review pushes it to the back of the backlog. Production answer: a strict
Content-Security-Policyheader with nonces, locked down for Contentful, the analytics provider, and the form endpoints. Solved in the starter — passes Mozilla Observatory A+ on day one. - 15. No documented migration path. The CMS schema drifts. Six months in, nobody can spin up a new environment that matches production. Production answer:
cf:migrate,cf:seed,cf:resetcommands with idempotent migration scripts checked into the repo. Solved in the starter — a new environment is five minutes, not five days.
Self-scoring
Want this kind of judgment on your project?
I read every email within one working day. Bring a project, a quote, or a system you're stuck on.
REST + GraphQL hybrids for multi-locale CMS-driven sites
Why neither REST-only nor GraphQL-only is the right call for an enterprise multi-locale CMS site, and how to split by concern instead. Includes the circular-reference problem on full REST payloads, the bundle cost of GraphQL on the client, the decision matrix per call site, the unified fetcher, granular cache tags, the block-as-fragment pattern, locale fallback in one round trip, Live Preview survival, Server Actions for CMA writes, the Algolia Sync API exception, and the migration sequence.
CMS-driven analytics: stop paying developers for every tracking change
How to structure your CMS so marketers can add tracking events without developer intervention. Save tens of thousands in ongoing costs.
Dynamic CMS linking: why your 'Link' field is a time bomb
Most CMS implementations let authors paste raw URLs. The day someone renames a slug, half your navigation silently 404s. The model that makes that impossible — with a Contentful walkthrough.