Every piece of marketing copy about "headless architecture" makes it sound like a solved problem: split the CMS from the frontend, get flexibility and performance for free. In practice, the decision that actually matters isn't whether to go headless — it's exactly where the line sits between the two halves.
What lives in Laravel, and why
On this project, Laravel owns everything that counts as a business rule: content, navigation, SEO metadata, pricing logic, publishing state. If a decision would need to change without a frontend deploy — an admin hiding a section, a price rule changing, a page being unpublished — it has to live on the backend. That's not a technology preference, it's a test we apply to every new field before we add it anywhere.
The section registry
The clearest example is how our own Services, Products, and Portfolio pages are composed. Instead of one fixed template per content type, each record picks which content blocks it uses and in what order, validated server-side against a registry of what's actually allowed in that context. The frontend never hard-codes "a service page looks like X" — it renders whatever the CMS says this particular service is made of.
What lives in Next.js, and why
Next.js's job is narrower than it sounds: fetch what Laravel returns, render it well, and get out of the way. Server components do almost all of the work; client-side JavaScript is reserved for things that genuinely need it in the browser — a lightbox, a magnetic hover, a share button — not for logic that could just as easily run on the server.
The payoff shows up in places that are easy to overlook until they go wrong: a content editor can reorder a page's sections without anyone touching code, and a visitor gets a server-rendered page whether or not their connection is fast enough to run much JavaScript at all.
The trade-off nobody advertises
Headless architecture means two systems to keep in sync instead of one. Every new field on the backend needs a matching type on the frontend; every resource needs to actually expose what the UI needs, not just what feels complete. We've caught real bugs this way — fields that existed in the database but were quietly missing from the API response, because nothing forced the two halves to agree. That coordination cost is real, and it's the actual price of the flexibility, not a footnote.



