Next.js
The React meta-framework this spoke inherited by charter from ../static-site-wiki and had never
paged — named in the synthesis as the most widely adopted instance of "the framework decides the
structure" and absent from the corpus until now. Read at v16.3.1, docs last updated 2026-07-21
(T1, first-party). Re-read 2026-09-22 at v16.3.6: same lastUpdated, same folder and file
conventions (app, pages, public, src; proxy.ts, instrumentation.ts). Release coverage of 16.3 was ingested separately on 2026-08-20 —
nextjs-16-3 — and adds a third axis to the split below.
The reason it matters here is not that it decides structure. It is that it decides exactly one half of it, and says so.
The half it decides: routing, by file convention
In the App Router, folders in app/ are URL segments and nesting folders nests segments. A set of
reserved filenames does the rest:
| File | Role |
|---|---|
page |
makes the route publicly accessible |
layout |
shared UI wrapping the segment and all descendants |
template |
a layout that re-renders on navigation |
loading |
React Suspense boundary |
error / global-error |
React error boundaries |
not-found |
the 404 UI |
route |
an API endpoint |
default |
fallback for a parallel route |
These render in a fixed order — layout → template → error → loading → not-found → page
— nested recursively so a child segment's components sit inside the parent's. Dynamic segments are
[slug], [...slug] (catch-all) and [[...slug]] (optional catch-all).
Three conventions do organizational work without touching the URL, and they are the ones this spoke should care about:
- Route groups
(folder)— omitted from the URL, used to group routes "by site section, intent, or team," and the mechanism for giving a subset of routes its own layout. Removing the top-levellayout.jsand putting one inside each group produces multiple root layouts, partitioning an app into sections with completely different UI. - Private folders
_folder— opted out of routing entirely, along with every subfolder. - Parallel
@slotand intercepting(.)/(..)/(...)routes — named slots a parent layout renders, and rendering another route inside the current layout without a URL change.
A route is not public until a page or route file exists, so anything else living in a route
folder is unreachable by construction. Colocation is safe by default; private folders are a
readability tool, not a safety one.
The half it refuses
"Next.js is unopinionated about how you organize and colocate your project files." The docs then
lay out three strategies without ranking them — keep app/ purely for routing and put code in root
folders; put shared code in top-level folders inside app/; or split code into the route segments
that use it — and close with "choose a strategy that works for you and your team and be consistent."
That third strategy is feature-first-structure offered as one option among three, by the framework with the largest install base in this category.
What this does to the spine's question
application-architecture asks who decides an application's division: the team, the organization, or the framework. wasp is the extreme answer — a compiler generates the structure and it "is not the author's to arrange." Next.js splits the question along an axis the spoke did not have:
- URL and rendering structure: the framework decides, non-negotiably, through file conventions that are also the API. There is no way to have a route without the folder that names it.
- Code organization: the framework declines, in writing, and hands it back.
So "the framework decides the structure" is true of Next.js only for the boundary the framework has to own anyway — the one where routing, layout nesting, error boundaries and streaming meet. The part flutter-large-app-structure argues about (where feature code lives, who owns state, which layer may import which) is exactly the part Next.js refuses to have an opinion about. Two of this spoke's sources are arguing about a question the dominant framework deliberately leaves open, which is a better explanation for why the argument persists than either source offers.
Worth noting against micro-frontends: route groups organize "by team" inside one deployable. Mezzalira's unit is a team that ships independently (micro-frontends-migration); a route group is a team that shares a build. Same organizational vocabulary, opposite deployment story.
What 16.3 changed about this reading (added 2026-08-20)
The two halves above came from the project-structure docs, which describe routing and decline code organization. nextjs-16-3 shows the framework deciding a third thing, and deciding it on its own schedule rather than the team's.
- Caching became structural.
cacheComponents: trueputs cache boundaries on components — where computation happens, what is reused across routes. It ships as an opt-in flag, and the release states the behaviour will become the default in a future major version. A team that never makes the choice still gets it. - A deployment target was retracted. The edge runtime is deprecated, following a rewrite of server rendering onto native Node.js streams.
- A structural option was foreclosed. Static exports do not work with Partial Prefetching, so shipping the app as static files now costs the framework's own navigation story.
None of this touches the refused half: where feature code lives and who owns state is still the reader's problem, and still unranked in the docs.
Related
nextjs-16-3 · application-architecture · feature-first-structure · wasp · micro-frontends · app-shell · boilerplate · flutter-large-app-structure · synthesis