Micro-Frontends Architecture for Agency Websites
As an agency site grows into a platform, with marketing pages, a portfolio engine, a client portal and a blog, a single monolithic front-end starts to slow every team down. Micro-frontends let independent teams ship independently, without stepping on each other.
Table of contents:
What micro-frontends solve
Micro-frontends extend the microservice idea to the browser. The interface is split into independently developed, tested and deployed pieces, so a team can release the pricing section without waiting on a full-site rebuild, and a failure in one module leaves the rest of the page standing.
The pattern earns its keep at organisational scale rather than on a five-page brochure site. The useful question is whether you have multiple teams whose release cadences are colliding. When the answer is yes, the coordination savings are substantial.
It also changes team ownership in a healthy way. Each module has a clear owner responsible for its code, its tests and its deployment, which removes the ambiguity that slows large shared codebases down. New engineers ramp on a single module rather than an entire monolith, releases become smaller and less risky, and a rollback affects one section instead of the whole site. Those organisational benefits are usually the real reason to adopt the pattern, and they compound as the number of teams grows.
Composition strategies
- Build-time composition. Modules published as packages and assembled in one build. Simple to run, though you redeploy the shell to ship any change.
- Server-side composition. Fragments stitched together on the server or edge for fast first paint and strong SEO.
- Runtime composition. Modules loaded in the browser, often through Webpack or Vite Module Federation, for genuinely independent deploys.
For a content and SEO driven agency site we usually favour edge or server composition for public pages, where first paint and crawlability matter most, and reserve runtime federation for the authenticated app areas where independent deployment pays off.
Keeping the bundle honest
The classic micro-frontend failure is shipping React three times because three modules each bundled their own copy. Share framework and design-system dependencies as singletons through your federation config, and enforce a shared version range so the whole page runs on one runtime. Audit the final network waterfall regularly, because it is the only reliable source of truth.
A shared design system, distributed as a versioned package and rendered through web components or a thin adapter layer, keeps the seams invisible. The site continues to feel like one coherent product.
Consistency, routing and communication
Independent modules still need to feel like one site. A lightweight application shell owns global routing, top-level navigation and shared state such as the current user, then hands control to whichever module owns the active route. Modules communicate through a narrow, explicit contract such as custom events or a small shared store, and keep out of each other's internals.
Design tokens, meaning colour, type and spacing expressed as shared variables, are what hold the visual language together even when different teams build different sections at different times.
Testing and observability across modules
Splitting the front-end multiplies the surfaces that can fail, so the testing strategy has to grow with the architecture. Each module owns its unit and component tests, and the shell owns contract tests that verify every module still honours the agreed interface. End-to-end tests then run against the fully composed application, which is the only place certain integration bugs ever appear. Skipping that layer is how a site that passes every module's own tests still breaks in production.
Observability matters just as much as testing. Attribute errors and performance metrics to the module that produced them, so a spike in one team's section does not read as a site-wide regression. Per-module source maps, and a shared error-reporting service tagged by module name, turn a confusing incident into a quick diagnosis. Real-user monitoring segmented the same way shows which team owns a slow route.
Versioning ties the whole approach together. Publish each module and the shared design system with semantic versions, and pin ranges deliberately so an urgent fix in one module never forces an unplanned release of another. Document the contract between shell and modules as carefully as you would a public API, because in a micro-frontend system that is exactly what it is. Clear contracts and clear versions let teams move quickly while staying out of each other's way.
When to reach for it
Micro-frontends add real operational overhead, including more build tooling, more deployment surface, and harder end-to-end testing. For many sites a well-structured modular monolith is faster to build and easier to run. Adopt micro-frontends when team autonomy and independent release velocity justify that cost.
Choosing the right architecture for your scale is exactly what we help clients get right, and we are glad to advise even when the honest answer is a simpler modular monolith. Explore our custom software development work, or start a conversation about your platform.