Synthesis — Frontend Architecture
The evolving thesis. This spoke was spun out on 2026-08-12 at the curator's approval, from three
sources that sat in the hub's holding pen over six weeks under the tag frontend-architecture:
flutter-large-app-structure (parked 2026-06-30), micro-frontends-migration (2026-07-14) and
open-saas (2026-08-10). Each had been declined by every existing spoke, and the declines are the
charter — see CLAUDE.md → Scope boundary.
Current thesis
One question, three answers, and the question is not technical. The founding sources all address who decides an application's structure, from three positions:
- the team, by convention — flutter-large-app-structure's feature-first-structure: capability at the top level, layers nested inside, features owning their own state.
- the organization, by ownership — micro-frontends-migration's micro-frontends: coarse-grained units, one team each, deployed independently.
- the framework, before anyone arrives — wasp through open-saas: a spec compiled into a whole application, its wiring not the author's to arrange.
Read together they say the decision does not vanish when it is delegated. Adopting a boilerplate is a structural choice, made by someone the adopting team will never meet.
Boundaries beat patterns
The two architecture sources agree on a claim neither one demonstrates. flutter-large-app-structure: "Large applications rarely fail because they lack patterns. They fail because ownership boundaries become unclear." micro-frontends-migration: micro-frontends optimize for independence, because "when you optimize for reusability, you create coupling." One is talking about folders and the other about deployables, and they arrive at the same sentence.
They also agree on a specific corollary — global state is the enemy, and features or units should own their own. Both name roughly the same exceptions (authentication, theme, localization). Two sources at different scales, in different ecosystems, converging on one rule is the strongest signal this small corpus currently holds.
Enforcement is what separates the two scales
A micro-frontend boundary is enforced by deployment: crossing it requires a
network call or a hard navigation. A feature-first-structure boundary is enforced by discipline:
nothing stops an import except review, or a tool of the kind micro-frontends-migration names
(ts-arch blocking unwanted imports, a bundle-size fitness function). The same thesis with two very
different amounts of teeth, and no source here compares how well each holds.
The most useful number in the corpus is not about modularity
One team went from 3 deployments a month to 25 a day per team after a micro-frontend migration — and micro-frontends-migration attributes it to the "safe net" of edge-compute canaries and rollback by configuration change, not to the architecture. Read carefully, the spoke's headline figure is evidence about reversibility. That is a caution against the reading everyone will want to make of it.
Duplication has a price, and one source pays it
"Duplication is far cheaper than the wrong abstraction" is a position, not a truism. The evidence offered is a shared header changed once in three years, against a team that spent four months shipping nothing to refactor global state. Thin, but it is arithmetic rather than taste, which is more than the rest of the domain manages.
The corpus's own weak spot
This is a domain that argues rather than measures, and the founding corpus shows it plainly. Of three sources: one is a practitioner reporting migrations he ran, with figures and named failures (T2); one is a first-party repository stating what it ships (T1, and promotional by construction); and one cites nothing at all — no study, no case, no measurement, no codebase named (T3, and its own page says so).
So the pattern to watch for is not disagreement between sources but confidence without evidence. A
structure diagram is not a finding. CLAUDE.md carries this as an edge rule: record what a source rests
on, every time.
Open questions
-
Does any of this reduce anything measurable? No source here reports a defect rate, a lead time, an incident count or a cognitive-load measure before and after a structural change. The one figure the corpus holds is a deployment frequency whose own author credits it to reversibility.
-
Which enforcement actually holds? Deployment-enforced boundaries versus review-enforced ones, over time, on the same team. Both founding sources assume their own answer.
-
What does a boilerplate cost later? open-saas pre-commits a dozen choices; nothing here describes a team hitting the limits of one, or the cost of leaving. The generous and the sceptical readings are equally unsupported.
-
Why did Open SaaS choose what it chose? The decisions are inspectable and the reasoning is absent. A maintainer's write-up would turn a template into an argument.
-
Is the "micro-frontends are microservices for the frontend" analogy load-bearing or decorative? The talk borrows a distributed-systems mindset explicitly. Whether the backend literature's findings transfer — or whether a frontend's constraints (one shared DOM, one user, page-load budgets) break the analogy — is untested here. Cross-spoke seam with
../platform-ops-wiki. -
Where do React meta-frameworks sit?
none of them paged— partly answered 2026-08-15 by nextjs (T1, v16.3.1), the first of the three. Remix and Gatsby are still absent, so the comparison the question wants is still impossible; what changed is that the category is no longer represented by zero sources. See the axis split below, and the schedule question nextjs-16-3 adds to it. -
What does it cost when a framework changes its mind? nextjs-16-3 deprecates a runtime and plans to make component-level caching the default. Nothing here describes a team absorbing that kind of change — how long it took, what broke, whether the structure they had chosen helped.
"The framework decides" is two claims, not one (added 2026-08-15)
The spine has treated who decides the structure as a single axis running from the team to the
framework, with wasp at the framework end: a compiler generates front-end, back-end and
deployment from main.wasp.ts, so the structure "is not the author's to arrange." nextjs, the
category's most-adopted member, does not sit anywhere on that line. It sits on both ends at once.
Routing structure: decided, absolutely. Folders are URL segments, page is what makes a route
public, layout nesting follows the folder tree, and the reserved filenames (layout, template,
error, loading, not-found, route) are simultaneously the API and the file layout. You cannot
opt out and keep the framework.
Code organization: refused, explicitly. The docs call Next.js "unopinionated" about how project
files are organized and colocated, then list three strategies without ranking them — code outside
app/, code in top-level folders inside app/, or code split into the route segments that use it —
and tell the reader to pick one and be consistent.
That third option is feature-first-structure, demoted from an argument to a menu item.
The consequence for this spoke is uncomfortable and worth keeping: the two sources that argue hardest about structure are arguing about the half the dominant framework deliberately leaves open. flutter-large-app-structure and micro-frontends-migration both concern where feature code lives, who owns state, and which unit ships — and none of that is what Next.js decides. It explains why the argument has no resolution better than either source does: there is no framework verdict to appeal to, because the framework declined to give one.
One vocabulary collision to keep straight. Route groups (marketing), (shop) organize routes "by
site section, intent, or team" — team-shaped folders inside one deployable. micro-frontends
means a team that deploys independently. Same word, opposite deployment story, and the distinction is
the one micro-frontends-migration spends its first section drawing against components.
The framework's decisions have a schedule (added 2026-08-20)
nextjs-16-3 complicates the section above enough to sit apart from it. Reading the docs gave a clean split — routing decided, code organization refused. Reading a release gives a third category: things the framework has not decided for you yet.
cacheComponents is the case. It puts cache boundaries on components, which is a question about
where computation happens and what is shared between routes — structural by any reading. Today it is
a flag a team opts into. The release says it becomes the default in a future major version. So the
honest description of the axis is not the framework decides versus the team decides, but who
decides, and when. wasp decides everything before the first line is written and is legible
about it. Next.js decides some things later, into a codebase already built on other assumptions.
Two smaller items from the same release sharpen it:
- The edge runtime is deprecated. A deployment target disappeared because server rendering was rewritten onto Node streams. No team chose that, and the migration is theirs.
- Static exports are incompatible with Partial Prefetching. Choosing static output now forfeits
the framework's own navigation story — the
../static-site-wikiseam, drawn from the meta-framework side and drawn as an exclusion.
And the evidence problem here is the mirror of the corpus's usual one. The spoke's standing complaint is that this domain argues without measuring. This source measures constantly — 90% less dev memory, 21.5 GB to 2 GB, 5.5× repeat builds, 22% more requests — and every one of those numbers belongs to vercel, which makes the framework and sells the hosting. The only independent readings are one early adopter relayed by The Register (~4 GB to 1.5 GB) and a Reddit thread. Meanwhile the best-evidenced part of the page is the list of things that break, which came from the project's own feedback discussion. Confident numbers from an interested party are not the opposite of confidence without evidence; they are the same gap wearing better clothes.
Enforcement has a third mechanism, and it is the weakest (added 2026-08-22)
The section Enforcement is what separates the two scales sets out two ways a boundary is held: deployment (crossing a micro-frontend boundary requires a network call or a hard navigation) and discipline (nothing stops an import into a feature-first-structure except review or a lint rule). module-federation — the mechanism micro-frontends-migration names four times without describing — belongs to neither.
Its boundary is enforced at runtime, by version negotiation in a share scope. Both sides must
agree on a shareKey or the negotiation silently does not happen and each ships its own copy;
singleton: true loads the higher version and warns whoever asked for the lower one; a
requiredVersion mismatch resolves to "the smallest version available" with a warning. So the
violation of this boundary is not a rejected import and not a review comment. It is two copies of
React on one page, or a framework silently upgraded under a team that did not ask — found in a
browser, in production, by whoever is looking.
That ranks the three honestly. Deployment enforcement fails loudly and early: the call does not compile or the network request 404s. Review enforcement fails quietly but locally: a bad import sits in one repository where a tool can find it. Runtime negotiation fails quietly and remotely, in someone else's application, at a moment nobody chose. And the corpus already holds the field evidence: micro-frontends-migration reports React Router against Module Federation needing a manual downgrade — this negotiation, resolved by hand.
The uncomfortable part is what shared is for. Micro-frontends are chosen for independence, on
the argument that "when you optimize for reusability, you create coupling." A share scope is
reusability, deliberately reintroduced, because shipping four copies of React is not tolerable. So
the tool the pattern is most often built on exists to soften the property the pattern is chosen for,
and nothing held here measures what that costs.
One smaller thing, on the spoke's own axis. Module Federation defines itself as "an architectural pattern for the decentralization of JavaScript applications (similar to microservices on the server-side)" — the analogy the open questions ask about, stated by the tooling as its definition rather than as a comparison. But the unit it federates is a module, so the same plugin serves a genuine team-owned deployable and an ordinary shared component library. Adopting it decides nothing about who owns what. Where wasp decides the structure and nextjs decides half and refuses the other half, this one decides nothing at all while describing itself as an architecture.
Enforcement has a fourth mechanism: capability grants at the plugin boundary (added 2026-10-05)
The three mechanisms held so far all police a boundary between the application's own parts: deployment
(a network call), discipline (review and lint) and runtime version negotiation (module-federation).
emdash-1-0 adds a boundary between the application and code its owner did not write, and holds it
differently. A plugin runs in its own isolate (a Dynamic Worker, or a workerd service on Node.js), starts
with private storage and nothing else, and every further reach (content, media, users, secrets, network)
is a permission the plugin declares and an admin approves.
That makes it the first boundary in the corpus that fails closed. A violation is a refused call, not two copies of React on a page. It also moves the decision, again: the framework does not choose the structure of the plugin, but it chooses the edges of every plugin, and the person approving a grant decides how wide the edge is. The decider is now a fourth party, the site admin, who is neither the team, the organization nor the framework author.
The registry half is the same idea one level up. Publishers keep their signed records in their own AT Protocol accounts and the catalog can only hide a listing, so no central party can rewrite a release. That is ownership by construction, the property micro-frontends gets from separate deployment, applied to distribution.
What it rests on: a vendor announcement and design argument. No audit, escape report or incident history is cited, and only free plugins exist, so the strong claim ("secure") is untested where it would matter, in a paid marketplace. The one operational figure (the Cloudflare Blog at 5,000 req/s) is Cloudflare describing its own site. Held at T3.
Growth edges
Ranked; each names the kind of source that would close it (see ../QUALITY.md → Growth edges).
- Any measured outcome of a structural choice. The spoke's thesis is currently unfalsifiable. — needs: a T1/T2 before-and-after on one codebase — defect rate, lead time, incident count or a validated cognitive-load instrument — not another architecture guide.
- The case against micro-frontends, from someone who tried them. Everything held is by an advocate. — needs: a published retrospective of a migration that was reversed or judged not worth it.
- Enforcement compared. (Now four mechanisms; the sandbox one has no failure data either.) — needs: an account of architecture-testing in practice (
ts-arch, dependency-cruiser, ArchUnit-style tools) with what it caught, or a study of import-boundary violation rates.
Coverage edges — things this spoke's domain plainly includes and does not hold; an ordinary solid source closes any.
- React meta-frameworks.
Next.js, Remix and Gatsby— one of three closed 2026-08-15: nextjs paged from its own project-structure docs (T1, v16.3.1). It did more than fill a hole, splitting the spine's axis in two (see above). — still needs: Remix and Gatsby, one page each from their own architecture documentation. Until then the spoke has one framework's answer and calls it the category's. - Monorepo versus polyrepo. micro-frontends-migration says the choice moves architecture, organization and culture together, and no page covers it. — needs: Nx or Turborepo documentation plus one migration account.
- The modular monolith. The position that says don't distribute, which the corpus needs in order for micro-frontends to be a choice rather than a default. — needs: a write-up arguing it, ideally with a codebase behind it.
Module Federation itself. Named repeatedly as the mechanism and never described.— CLOSED 2026-08-22 by module-federation, from the project's own docs and repository (T1, v2.8.2). A coverage edge closing cleanly on first contact, which is the third time that has happened here against zero clean closes for a question edge. It also did more than fill the hole: thesharedscope is a third enforcement mechanism, and the spine section above ranks it below both of the two it already held.- What runtime sharing costs. HALF-CLOSED 2026-08-25 (research pass) by
module-federation-singleton-postfix-bug (module-federation/core #4078, T1): a semver prerelease
suffix defeats
singleton: true, every remote loads its own copy, and the consumer had asked for*. The reporter's own control — drop the suffix and it works — makes it a defect rather than a misconfiguration. It confirms the enforcement finding with a case and supplies a trigger nobody would guess, and the report was closednot_plannedby an inactivity bot, so a team evaluating this architecture meets no artifact warning them first. Successor (edge 8a): still no accounting. That incident carries no measurement — no duplicated bytes, no time-to-detection, no downstream effect on the team that was upgraded under. — needs: a duplicate-bundle measurement across a federated application, or a post-mortem that states how long a two-instance state ran before anyone noticed. The vendor-consultancy write-ups that carry figures of this kind (11.9 MB bundles, a 7.5 → 10.5 MB regression) were found on 2026-08-25 and rejected at the bar — all T3 marketing for migration services, with no stated method.
Contradictions / tensions
No factual conflicts yet — three sources at three scales, largely non-overlapping. The live tension is about genre, and it was live before the spoke existed: two founding sources are architecture guides that argue a thesis; open-saas is a template that embodies one silently, and the hub's own park record noted that the same cluster had already excluded a build-along tutorial on exactly that distinction. The spin-out went ahead with the objection recorded rather than dissolved (boilerplate). Expect it to recur: this domain's artifacts are guides, repositories and talks, and they support very different kinds of claim.
Cross-spoke adjacency
../ui-frameworks-wiki— the layer below. The component-versus-micro-frontend distinction is the seam, and micro-frontends-migration draws it explicitly.../static-site-wiki— that spoke's exiled React meta-frameworks belong here; its build-time SSGs do not.../platform-ops-wiki— edge-compute canaries, Strangler Fig rollout and the distributed-systems mindset micro-frontends borrows.../webperf-wiki— the "micro-frontend bundle ≤ 30 kilobytes" fitness function: a byte budget used as an architectural boundary check.../dev-tooling-wiki— Module Federation, bundlers and monorepo tooling as infrastructure; the structures they enable are here. nextjs-16-3's Turbopack disk cache and TypeScript 7 support are theirs; see typescript-7-go-compiler for the compiler numbers, which are measured rather than relayed.../static-site-wiki, again — emdash-1-0 is built on astro but is a server-rendered CMS, the kind of Astro-based product that spoke's charter sends here.../cloud-wiki— cloudflare sells the runtime emdash-1-0's plugin isolation is designed around; same vendor-and-host pattern as vercel below.../cloud-wiki— vercel as a hosting business. Relevant here because the framework's new default is the feature that self-hosting reportedly breaks on.
Index — Frontend Architecture Wiki
Catalog of every page, grouped by schema.org
@type. Spine: synthesis (thesis),log.md(history), this file (catalog). Spun out of the hub_inboxon 2026-08-12 from three sources parked over six weeks. This domain argues more than it measures — record what each source rests on (a migration the author ran, a codebase they shipped, or reasoning alone), and keep the tier honest.
DefinedTerm (concepts / patterns)
- application-architecture — the umbrella: how a client-facing application is divided into parts and who decides the division — the team, the organization, or the framework; the axes are grain, state ownership, where composition happens, what is duplicated on purpose · domain
- micro-frontends — coarse-grained, self-contained, independently deployed units, one team each; defined against the component ("when you optimize for reusability, you create coupling"), and the decisions it forces: vertical/horizontal split, shell vs composer, routing altitude, event emitters over global state · architecture-pattern
- feature-first-structure — capability at the top level with layers nested inside; features own their state, constructor injection over service locators, and the invariant that business rules must not depend on HTTP or serialization · architecture-pattern
- app-shell — the thin long-lived host owning configuration, authorization, composition and routing; the spec is stability — "an application shell that doesn't change very often after one year" · mechanism
- boilerplate — the starter template as an architecture artifact: a dozen decisions arriving as a bundle, inspectable but unexplained; the class where the deciding party is absent · artifact-class
SoftwareApplication
- nextjs — the React meta-framework the spoke inherited by charter and had never paged (v16.3.1, docs 2026-07-21). App Router file conventions decide routing structure absolutely (
pagemakes a route public; route groups(folder)organize by team without touching the URL;_folderopts out) and the docs call Next.js "unopinionated" about code organization, offering three strategies unranked. Splits the spine's question into an axis the spoke lacked ·source· T1 · nextjs.org · 16.3 update 2026-08-20 (nextjs-16-3): caching becomes structural, edge runtime deprecated, static export foreclosed - wasp — declarative full-stack framework with a compiler:
main.wasp.tsgenerates front-end, back-end and deployment, so the structure is not the author's to arrange. 18.7k★, v0.24.0, beta; React + TanStack Query / Node + Express / Prisma only ·source· T1 · github.com
NewsArticle (sources)
-
nextjs-16-3 — Daniel Curtis, infoq, 20 Aug 2026, on Next.js 16.3: Turbopack disk caching + memory eviction on by default (up to 90% less dev memory; Vercel's dashboard 21.5GB→2GB), repeat CI builds 5.5× faster, SSR on native Node streams (+22% requests, edge runtime deprecated), TypeScript 7 support, and opt-in Instant Navigations (
cacheComponents+partialPrefetching, default in a future major). Breaks: static exports,styled-jsxleakage, self-hosted SST. Every figure is vercel's own ·source· T3 · infoq.com -
emdash-1-0 — Cloudflare Blog, 28 Sep 2026: EmDash 1.0, an MIT, Astro-based server-rendered CMS (not an SSG). Plugins run isolated (Dynamic Workers, or
workerdon Node) with private storage and no reach into content, users, secrets or network unless declared and admin-approved; plugin registry on AT Protocol with signed releases. The spine's fourth enforcement mechanism, failing closed. Vendor announcement, no audit cited; only free plugins ·source· T3 · blog.cloudflare.com
SoftwareSourceCode (sources)
- module-federation-singleton-postfix-bug — module-federation/core issue #4078 (filed 2025-09-18, closed 2025-12-02
not_plannedby theno-issue-activitybot): a semver prerelease suffix (2.2.2-release.99) stopssingleton: truebeing honoured, so every remote loads its own copy and the symptom is two Reacts in a page rather than an error. The spoke's first named version-negotiation incident — the runtime-enforcement finding happening to somebody ·source· T1 · github.com - module-federation —
module-federation/core, MIT, 2,618★/430 forks, v2.8.2 (2026-08-06), Rspack + Webpack. The mechanism micro-frontends-migration names repeatedly and never describes, read from its own docs: producer/consumer +exposes/remotes, a runtime manifest, and thesharedscope where the real difficulty lives (shareKeymust match on both sides or negotiation silently fails;singletonsilently upgrades the lower version and warns; arequiredVersionmismatch takes "the smallest version available"). Calls itself "an architectural pattern for the decentralization of JavaScript applications" — a pattern claim made by a build plugin. Adds a fourth kind of boundary enforcement to the spine's two: runtime version negotiation, whose violations surface as console warnings in production ·source· T1 · module-federation.io - open-saas — wasp-lang's MIT SaaS boilerplate, 15.3k★/1.8k forks/101 open issues (re-verified 2026-08-12): auth (5 providers), payments (Stripe/Polar.sh/Lemon Squeezy), jobs, ShadCN admin, S3, email, analytics, Playwright, Astro Starlight docs, Railway/Fly.io deploy — plus an
AGENTS.md/skills/Claude Code plugin surface ·source· T1 · github.com
PresentationDigitalDocument (sources)
- micro-frontends-migration — Luca Mezzalira (AWS), QCon San Francisco 2025 via InfoQ, from hundreds of migrations: the component/micro-frontend distinction, the six-step framework, Strangler-Fig rollout on edge compute with rollback by configuration (3 deploys a month → 25 a day per team), "duplication is far cheaper than the wrong abstraction," and the socio-technical claim ·
source· T2 · infoq.com
Article (sources)
- flutter-large-app-structure — Ethiel ADIASSA, freeCodeCamp, 23 June 2026: feature-first layout, three layers per feature, feature-level state ownership, constructor DI. "Large applications rarely fail because they lack patterns. They fail because ownership boundaries become unclear." Cites no study, case or measurement ·
source· T3 · freecodecamp.org
Person (entities)
- luca-mezzalira — Principal Solutions Architect at aws; the spoke's only source of figures from work actually done, and the standing caution that his employer sells the edge compute his safest technique runs on
EducationalOrganization (entities)
- freecodecamp — non-profit learning platform; publisher of contributed practitioner articles, which is the genre flutter-large-app-structure belongs to
Synthesis
- synthesis — one question (who decides an application's structure), three answers, and a domain that argues more than it measures