How To Keep Your Website Fast When You Add More Features
Adding features as separate mini-apps duplicates code, breaks the design and slows every visit. One modular codebase avoids all three.
Splitting a site into separately deployed mini-apps duplicates code, fractures the design system and slows every visit; one modular codebase with islands gives you the same separation without the tax.
Adding a Feature Should Not Slow the Site Down
Here is the shape of it. The business is doing well, so you add a booking form. A few months later someone asks for a pricing calculator, so a different agency builds it. Then reviews, then a chat widget, then an online shop. Each one arrives as its own small application, in its own repository, built by whoever was available.
The site now works. It also takes noticeably longer to open on a phone, the buttons no longer quite match, and the last change took three weeks because four codebases had to be coordinated.
┌──────────────────────────────────────────────────────────────────────────────┐
│ HOW A SMALL SITE ENDS UP WITH SEPARATE MINI-APPS │
├──────────────────────────────────────────────────────────────────────────────┤
│ BROWSER (one phone, one CPU thread, a cellular connection) │
│ ├─ Host shell (loads the orchestration code) │
│ ├─ Navigation app (React, plus a component library) │
│ ├─ Pricing calculator (Vue, plus a different component library) │
│ ├─ Reviews widget (its own framework version, its own CSS reset) │
│ └─ Chat tool (a script from another vendor) │
├──────────────────────────────────────────────────────────────────────────────┤
│ WHAT THE VISITOR PAYS FOR: the same library downloaded two or three │
│ times, in different versions, before they read a single word. │
├──────────────────────────────────────────────────────────────────────────────┤
│ WHAT YOU PAY FOR: five codebases, five places to break, five invoices. │
└──────────────────────────────────────────────────────────────────────────────┘
These patterns were designed for backend systems with hundreds of engineers and enormous server budgets. Copying them into a small business website is like building a warehouse to store a bicycle.
The fix is not to stop adding features. It is to add them inside one codebase.
1. What Actually Goes Wrong
A. Several runtimes, one phone
For each mini-app to be deployed independently, each one is usually allowed its own dependency versions. In practice that means the browser downloads two or three copies of the same JavaScript library, because nobody was in a position to make them agree.
The browser has to download, parse and run all of it before your page settles. On a mid-range phone that is one CPU thread doing layout, input handling and garbage collection at the same time. The page feels slow even when the network is fast, and the delay lands exactly where it hurts: between the tap and the response.
B. The design quietly drifts
Micro-apps promise a shared component library. In practice, versions drift. One part of the site is on version 2 of the design system, another is on version 3, and you get two different button weights, a tooltip that hides behind the header, and two CSS resets arguing with each other.
The site no longer looks like one business, and nobody chose that. It just drifted.
C. Crawlers can find nothing
Search crawlers and AI ingestion tools do not wait for a page to assemble itself in the browser. When the content is rendered client-side, they can encounter an empty shell and move on. The page you wrote may not be the page that gets read.
D. Changes become expensive
Now every change touches several codebases, several staging environments and several deploys. A small break in one piece can surface in production without appearing in any test. The owner’s experience of this is simple: a small change takes weeks, and the estimate keeps moving.
2. The Alternative: One Codebase, Islands
The opposite approach is a modular monolith: one repository, one build, one deploy, with the site split into clear folders that each own a job.
┌─────────────────────────────────────────────────────────────────────────────────┐
│ ONE CODEBASE, SPLIT INTO CLEAR PARTS │
├─────────────────────────────────────────────────────────────────────────────────┤
│ apps/site/ (the Astro site) │
│ ├── src/pages/ -> plain HTML pages, no JavaScript by default │
│ └── astro.config.mjs -> one compile step for the whole site │
│ │
│ packages/ │
│ ├── @site/domain-catalog/ -> product data and page schemas │
│ ├── @site/domain-calculators/-> the interactive bits, as isolated islands │
│ ├── @site/domain-editorial/ -> written content, typed and checked │
│ └── @site/design-system/ -> CSS tokens, no runtime, one source of truth│
├─────────────────────────────────────────────────────────────────────────────────┤
│ ONE BUILD: shared dependencies are loaded once, not four times. │
│ ONE DEPLOY: the whole site goes live together, or not at all. │
└─────────────────────────────────────────────────────────────────────────────────┘
Four ideas make this work:
- Everything is assembled at build time. Modules are combined during the build, and the compiler outputs a single copy of every shared library. If two parts of the site use the same component, there is one version of it.
- Clear ownership inside one repository. Each package has one job, and the boundaries are enforced by the type system, so a change in the shop does not quietly alter the booking page.
- Only interactive parts ship JavaScript. A pricing calculator needs to run in the browser, so it hydrates on the page where it appears. Everything else ships as static HTML with no script at all.
- One atomic deploy. The site is built once and published as an immutable set of files, so a failure in one part cannot take down the rest.
3. What That Looks Like in Code
The structure is a workspace, not a set of separate projects:
// pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
- 'modules/*'
And a page that is static by default, with one interactive component:
---
// apps/site/src/pages/services.astro
import BaseLayout from '../../layouts/BaseLayout.astro';
import { Hero } from '@site/design-system';
import { ScopeEstimator } from '@site/domain-calculators';
import { getCollection } from 'astro:content';
// Content is compiled at build time
const caseStudies = await getCollection('case-studies', ({ data }) => data.featured);
---
<BaseLayout title="What We Do">
<!-- Static header and hero: no JavaScript -->
<Hero
title="Websites, stores and small automations"
kicker="Services"
/>
<!-- The only interactive part, and it hydrates when it scrolls into view -->
<ScopeEstimator client:visible />
<!-- Static content section -->
<section class="case-studies-grid">
{caseStudies.map((study) => (
<article class="study-card">
<h3>{study.data.title}</h3>
<p>{study.data.summary}</p>
</article>
))}
</section>
</BaseLayout>
The point of the last example: the estimator is a component, not a separate application. It shares the design system, shares the build, and ships its JavaScript only when it is on screen.
4. The Numbers You Can Check Yourself
Do not take anyone’s word for how fast a site is, including this one. Open the tools and measure.
| What to measure | Where to measure it | What you want to see |
|---|---|---|
| JavaScript shipped per page | DevTools, Network tab, filter by JS | A small total, not hundreds of kilobytes of frameworks |
| Duplicate libraries | DevTools, Network tab, search the same file | One copy of each library, not three versions of it |
| Largest Contentful Paint | PageSpeed Insights, run it on mobile | Under 2.5 seconds, and under 1 second is achievable |
| Interaction to Next Paint | Lighthouse, or a slow 4G test | Under 200ms |
| Build and deploy time | Your CI log | A couple of minutes, not half an hour |
| Number of codebases | Ask whoever maintains it | One |
Run those six checks before and after any feature you add, and you will not need a benchmark table from a blog to tell you whether the change was worth it. If you want the commercial side of the same question, why a faster website means more enquiries covers what the research actually shows.
Conclusion: Add the Feature, Not Another Application
A site does not get slow because it has more features. It gets slow because each feature arrives in its own codebase, with its own framework version, its own copy of the design system and its own deploy.
Keep one codebase. Make each new thing a component inside it, let the build handle the rest, and measure what you ship.
One codebase, one build, and JavaScript only where you actually need it.
Frequently Addressed Technical Inquiries
What is the micro-frontend antipattern in public web architecture? [+]
The micro-frontend antipattern occurs when teams apply distributed microservice patterns directly to the client browser. On public websites and client portals, this forces the browser to download multiple isolated framework runtimes (e.g., three separate versions of React, multiple design system stylesheets, duplicate state managers), destroying Core Web Vitals, causing layout thrashing, and fracturing SEO discoverability.
What is a Modular Monolith in modern frontend engineering? [+]
A Modular Monolith is a unified, single-repository architecture where business domains (e.g., checkout, documentation, marketing, customer portal) are organised into isolated compile-time packages or directories with strict boundaries. Unlike distributed runtimes, a modular monolith compiles into a single, highly optimised static output with shared dependencies and zero runtime federation overhead.
How does Astro solve team autonomy without micro-frontend runtime penalties? [+]
Astro allows different parts of the site to be authored using their preferred tools (React, Vue, Svelte, or native HTML) within independent workspaces or packages, but compiles them into zero-JavaScript static HTML at build time. Dynamic features run as isolated client islands only where necessary, avoiding runtime iframe sandboxing or Module Federation latency.
Related articles
Audit canonical and hreflang in an Astro website
Reproduce a missing hreflang return link, export an audit to JSON, and verify the correction with Aura Logic's open-source SEO CLI.
Answer Customer Questions Without Hiring a Support Team
Put clear service pages, guides and self-service tools on your website so repeat questions stop eating your week and your margin.
Capital Efficiency: Asynchronous Operations for Small Teams
Asynchronous work for small teams: written briefs and protected focus blocks that cut meeting time and let a lean studio deliver more without hiring.
WANT IT REVIEWED FOR YOUR BUSINESS?
The above is general. Tell me about your business and I will review business websites for your case: what applies, what does not, and in what order.
Business websites ↗TELL US ABOUT
YOUR BUSINESS.
Tell us what your business does, what you need and your approximate budget. We will review the scope and next steps with you.
READY TO IMPROVE YOUR WEBSITE?
Describe what you want your website to do for your business. Jorge will help you define the scope, understand the cost and choose the next step.