Why Micro Frontend?
Micro frontend solves a people problem, not a technical one: many teams stuck behind one shared release. See it happen - four teams, one release script, and one team’s red test blocking another team’s urgent fix - then the same teams with separate releases, and a 250-day simulation of how often each setup can ship.
What you will be able to do
- Explain the release-train problem in plain words
- See one team block another in a shared release
- See the same teams release independently
- Estimate how often a shared release is possible
- Name what micro frontend does NOT fix
The idea, in plain English
Most frontend problems are technical: slow pages, bugs, messy code. Micro frontend is different. It does not make code faster or cleaner. It solves an organisation problem: when many teams work on one frontend that is built and released as one thing, every team waits for every other team.
This waiting has a name: the release train. All changes leave together, on one train, when everything is ready. One team’s unfinished work or one red test stops the train for everyone - including a team with an urgent bug fix. The more teams, the more often something is red.
We make this concrete with Node’s built-in test runner: one release script for four teams, then one release script per team, and a small simulation over 250 working days. No frameworks - the problem shows up without them. Node 22.
Worked example: Four teams - cart, search, catalog, account - first blocked behind one release train, then releasing on their own.
Words you will see in this lesson
A few words about teams and releases.
Release trainAll changes are released together, at one time, as one package.Green / redTests pass / tests fail.HotfixAn urgent fix that must go live quickly.AutonomyA team can decide and release without asking other teams.Coordination costThe time teams spend waiting for, and agreeing with, each other.An everyday example: a school bus
- One school bus picks up every child. If one child is late, the whole bus waits - and every child is late to school.
- The more children on the bus, the more often someone is late.
- If each family drives its own child, a late child makes only that child late.
- But now there are many cars, many drivers and a traffic jam at the gate - independence has a cost too.
Example 1 - four teams, one release
monolith/ has four teams’ code in one place and ONE release script:
- Team Checkout fixed a real bug in cart.js - its test passes.
- Team Search merged half-finished work on Monday - a new ranking that reverses the results. Its test fails.
- release.mjs runs every team’s tests with node --test. If any test fails, nothing is released.
- Result: RELEASE BLOCKED by "search keeps the shop order". The cart fix waits - for a problem that has nothing to do with the cart.
// Team Checkout - URGENT FIX: the total was wrong for 2+ books
export const total = (prices) => prices.reduce((sum, p) => sum + p, 0);
// Team Search - half-finished work: a new ranking, merged on Monday
export const search = (books, q) => books.filter((b) => b.includes(q)).reverse();import { test } from 'node:test';
import assert from 'node:assert';
import { search } from './search.js';
test('search keeps the shop order', () =>
assert.deepEqual(search(['Python 1', 'Python 2'], 'Python'), ['Python 1', 'Python 2']));// ONE release for the whole frontend: every team's tests must pass.
import { execSync } from 'node:child_process';
try {
execSync('node --test --test-reporter=tap "teams/*.test.js"', { stdio: 'pipe' });
console.log('RELEASED: all four teams go live together');
} catch (error) {
const failed = error.stdout.toString().split('\n').filter((line) => line.trim().startsWith('not ok'));
console.log('RELEASE BLOCKED - failing tests:');
failed.forEach((line) => console.log(' ' + line));
console.log('Nothing goes live - not even the cart fix.');
}$ node release.mjs
RELEASE BLOCKED - failing tests:
not ok 4 - search keeps the shop order
Nothing goes live - not even the cart fix.Example 2 - the same teams, separate releases
split/ has the same code, but each team has its own folder, and the release script takes a team name:
- node release.mjs cart runs only the cart tests - and released the fix.
- search was blocked - but only search.
- catalog and account released too.
- Nothing in the code changed. Only WHO decides about a release changed: each team, for its own part.
// ONE release per team: only that team's tests decide.
import { execSync } from 'node:child_process';
const team = process.argv[2];
try {
execSync(`node --test --test-reporter=tap "${team}/*.test.js"`, { stdio: 'pipe' });
console.log(`RELEASED: ${team} is live - no other team was involved`);
} catch (error) {
const failed = error.stdout.toString().split('\n').filter((line) => line.trim().startsWith('not ok'));
console.log(`${team} BLOCKED - failing tests:`);
failed.forEach((line) => console.log(' ' + line));
console.log('Only this team waits. Everyone else can still release.');
}$ node release.mjs cart
RELEASED: cart is live - no other team was involved
$ node release.mjs search
search BLOCKED - failing tests:
not ok 1 - search keeps the shop order
Only this team waits. Everyone else can still release.
$ node release.mjs catalog
RELEASED: catalog is live - no other team was involved
$ node release.mjs account
RELEASED: account is live - no other team was involvedExample 3 - how often can you release?
release_days.mjs simulates 250 working days. On each day, each team’s tests are green with a 90% chance:
- A shared release needs all four green on the same day: possible on 163 of 250 days.
- A team’s own release needs only its own tests: possible on 221 to 225 days.
- With 10 teams instead of 4, the shared train gets much worse - each new team is one more thing that can be red.
- This is why the problem is about team COUNT. One team gains nothing here.
// 250 working days. Each day, each team's tests are green with 90% chance.
let seed = 42;
const random = () => ((seed = (seed * 1103515245 + 12345) % 2 ** 31) / 2 ** 31); // repeatable
const teams = ['cart', 'search', 'catalog', 'account'];
const days = 250;
let trainDays = 0; // one release for everyone
const ownDays = Object.fromEntries(teams.map((t) => [t, 0])); // one release per team
for (let day = 0; day < days; day++) {
const green = teams.map(() => random() < 0.9);
if (green.every(Boolean)) trainDays++;
teams.forEach((t, i) => { if (green[i]) ownDays[t]++; });
}
console.log(`one shared release: possible on ${trainDays} of ${days} days`);
for (const t of teams) console.log(`${t.padEnd(8)} own release: possible on ${ownDays[t]} of ${days} days`);one shared release: possible on 163 of 250 days
cart own release: possible on 225 of 250 days
search own release: possible on 222 of 250 days
catalog own release: possible on 223 of 250 days
account own release: possible on 221 of 250 daysWhat micro frontend does NOT fix
Independent releases move the cost; they do not remove it:
- Slow pages - often slower: more files, maybe several copies of a library (Lesson 3 measures it).
- Bad code - each piece can still be messy.
- Unclear teams - if nobody knows who owns the cart, splitting the code does not help.
- Coordination - it moves from "waiting for the train" to "agreeing on contracts", like mount(element) in Lesson 1.
- Before micro frontend, try the cheaper fixes: feature flags so half-done work can be merged switched off, faster tests, and a rule that red builds are fixed first.
The release problem at a glance
Shared releaseEveryone must be green.
node --test "teams/*.test.js"
Own releaseOnly this team decides.
node --test "cart/*.test.js"
Chance all greenFalls with every team.
0.9 x 0.9 x 0.9 x 0.9 (4 teams)
Cheaper fix firstMerge but hide.
if (flags.newRanking) { ... }Try it yourself
The code does not change. Swap the content string and the program does something else entirely.
“Create the two folders and run node release.mjs in monolith/, then node release.mjs cart in split/.”
“In release_days.mjs, use 10 teams. On how many days is a shared release possible now?”
“Change the chance from 0.9 to 0.98. How much does the shared release improve?”
“Put Search’s new ranking behind a flag that is off by default. Does the monolith release now?”
What usually goes wrong
It solves release coupling between teams, not performance.
If ownership is unclear, separate releases just spread the confusion.
Feature flags and faster tests often solve the release train for far less.
Separate releases need contracts between pieces - and someone to own them.
Practice
Write these yourself before opening anything. Getting them wrong first is most of how this sticks.
Extend release_days.mjs to print a small table: for 1, 2, 4, 8 and 16 teams, how many of 250 days allow a shared release, and the average number of days each team could release on its own. Then write two sentences: at which team count would you start to consider separate releases?
Show hintHide hint
Wrap the loop in a function simulate(teamCount) and reset the seed at the start of each run so the results are repeatable.
Key points
- Micro frontend solves an organisation problem: teams blocked behind one release.
- In a shared release, one team’s red test blocks everyone - including urgent fixes.
- The more teams, the less often everyone is green at once.
- Separate releases let each team ship when its own part is ready.
- The cost moves to contracts and coordination; it does not disappear.
- Try feature flags and better tests first.
Quick check before you move on
Interview questions
Why would an organisation adopt micro frontends?
To let multiple teams aligned to business domains develop, test and deploy their parts of the UI independently, removing a shared release train as the bottleneck - accepting more integration and operational complexity in return.
What would you try before micro frontends?
A modular monolith with clear ownership boundaries, trunk-based development with feature flags, fast and reliable CI, and possibly separate deployable apps per area - micro frontends only when release coupling across many teams remains the main pain.
Quiz
- 1.
Why does a shared release get worse as teams are added?
- 2.
Name two cheaper fixes to try before micro frontend.
- 3.
Where does the coordination cost go with separate releases?
Comments
Sign in to leave a comment. Your name and photo come from Google; nothing else is shared.
Loading comments...