What you'll learn: By the end of this lesson you will be able to describe a front-end system as a set of layers between a person's device and the back end, explain five ways front-end design differs from back-end design, name the decisions a front-end architect makes, and see how this course and the back-end System Design course fit together.
Think of a restaurant, but look at the dining room instead of the kitchen. In the kitchen you control the stoves, the staff and the schedule. In the dining room, guests arrive hungry or in a hurry, sit where they like, and leave halfway through if the food is slow. You cannot control them, and every guest is a little different.
The front end is that dining room. It runs on someone else's device, over someone else's network, in front of a person who has no interest in how it works.
The running example is an online store with a product page (photos, price, stock, an "Add to basket" button) and a checkout (address, payment, confirmation). Every later lesson returns to it.
The core idea
A front-end system is everything between a person's device and your back-end services: the code that runs in the browser, the network that carries it there, the servers and caches that deliver it, and the practices that keep it fast, safe and working after you ship it.
Many developers hear "front end" and think "components and CSS", which is one layer. "The product page is slow" might come from a large image, a late server, a blocking script, a cache miss or a busy phone. Front-end system design means seeing all of these and deciding which you own.
Figure 1. A front-end system spans the device, the network and delivery, and ends at the back-end APIs.
How to read this: the shaded zone is where your code runs and where you have the least control. Everything to its right is infrastructure you configure. The back-end APIs are where this course hands over to the System Design course.
How front-end design differs from back-end design
The two share goals: be fast, be correct, survive failure. The difference is the conditions. Five shape almost every front-end decision.
- The runtime is a device you do not control. Front-end code runs on whatever the shopper owns. At the time of writing the Baseline "core set" of browsers is Chrome, Edge, Firefox and Safari, built on different engines (Chromium, Gecko, WebKit), so the same code can behave a little differently. Baseline and MDN's compatibility tables say which features are safe.
- One copy of your code runs on many devices at once. A back-end release replaces code on your servers. A front-end release reaches whoever opens the page next, while people with the page already open keep the old version.
- There is one main thread. Most of your JavaScript, the work of building the page and the handling of taps share a single thread. While a task runs, the browser cannot respond to input. A page cannot add a second main thread.
- State is per person. A back end mostly manages shared data such as orders and stock. A front end also holds state that belongs to one tab: what is in the form, which tab is selected, what is loading.
- Failure is ordinary. Networks drop or slow down and scripts fail to load. You design so the page does something sensible when they do.
| Concern | Back-end design | Front-end design |
|---|---|---|
| Where code runs | Machines you choose and size | Devices and browsers you do not control |
| Release | Replace code on your servers | Ship to many users, some holding an old version |
| Concurrency | Many requests in parallel, scale out | One main thread per page, work must be split up |
| State | Mostly shared data | Shared data plus per-tab UI state |
| Typical failure | Overload, a dependency down | Slow or offline network, script failure, old browser |
| Visibility | Your logs and metrics | Only what the page sends back |
| Trust | You can enforce rules | The device's owner can read and alter what runs there |
The last row matters. MDN's form validation guide says client-side validation is too easy to bypass to count as a security measure, so the server must validate too. The front end makes the experience good; the back end enforces the rules.
A layered model of a front-end system
This course uses one model to ask "where does this problem live?". It is a teaching tool, not a standard; teams draw the layers differently.
Figure 2. The layers of a front-end system, with four concerns that cut across all of them.
How to read this: the top row follows a page from the moment it is built to the moment it asks for data. The bottom row is not a step; each of those four concerns applies at every layer above it.
| Layer | What lives there | A question it raises on the store |
|---|---|---|
| Delivery | Build output, file names, CDN, release process | How do we ship a price-display fix without breaking open tabs? |
| Network | HTTP requests, caching headers, connections | Which files can the browser keep, and for how long? |
| Browser runtime | HTML parsing, layout, paint, the event loop | Why does the page jump or freeze while images load? |
| Application | Components, routing, rendering strategy | Is the product page built in the browser or on a server? |
| State and data | Where data is fetched, cached and held | Who owns the basket: the page, the server, or both? |
Trace a symptom down the layers: "checkout feels slow" can be a large bundle (delivery), missing caching (network), a long task blocking taps (runtime), too much rendering (application) or sequential requests (data).
One page load, end to end
Here is what happens when a shopper opens a product page in a client-rendered design. Later lessons explain each step.
Figure 3. Loading a product page and adding an item to the basket.
and stylesheets B->>C: GET app and style files C-->>B: JS and CSS Note over B: run JS on the main thread B->>A: GET /api/products/42 A-->>B: JSON (name, price, stock) Note over B: build the page,
lay out, paint S->>B: tap Add to basket B->>A: POST /api/basket A-->>B: updated basket
How to read this: time runs downward. In this design the shopper sees nothing useful until the browser has the HTML, the files it references and the data. Each arrow can be slow or fail, and each note is work on the one main thread.
The order is a choice, not a law. Some products build the HTML on a server so the first response already contains the product; others generate it ahead of time. web.dev's Rendering on the Web names the options (client-side, server-side and static rendering, and hybrids) and their trade-offs; the Rendering Strategies lesson covers them.
The decisions a front-end architect makes
You will meet these eight decisions repeatedly. Each is a trade-off, and each is touched by a lesson in this course or a planned later course.
| Decision | The question | Where it is covered |
|---|---|---|
| Rendering strategy | Where and when is the HTML produced: in the browser, on a server per request, or ahead of time? | Rendering Strategies (CSR, SSR, SSG, ISR, streaming) |
| Data fetching and caching | What does the page request, when, and which copies may be reused? | HTTP Caching for the Front End; the planned data and APIs course |
| State ownership | Does a piece of state live in the URL, a component, a client store or the server? | The planned React and state course |
| Code splitting and shipping | How is code divided, and what must the first visit download? | HTTP Caching for the Front End (shipping hashed files); Loading Performance and Core Web Vitals (how splitting affects LCP and INP) |
| Performance budget | What limits do we set, and who is told when a change breaks them? | Loading Performance and Core Web Vitals |
| Accessibility | Can a person with a keyboard or screen reader complete checkout? | Frontend Requirements: Users, Devices and Networks; the planned case studies |
| Security boundary | What may run in the page, and what does the server check? | The planned security course |
| Observability | How will we learn something broke on a device we cannot see? | Loading Performance and Core Web Vitals; the planned later courses |
Two terms. A performance budget is, in web.dev's words, a set of limits imposed on metrics that affect site performance; the limits can be on quantities (script size), milestone timings (First Contentful Paint) or tool scores (Lighthouse). Accessibility is, in MDN's definition, the practice of making websites usable by as many people as possible, which also helps people on mobile devices or slow connections.
Why one main thread matters
MDN's event loop article explains that each job runs to completion before the next starts, and that a job that runs too long stops the page processing clicks and scrolling. web.dev defines a long task as one that runs longer than 50 milliseconds and says it can delay a tap's visible response until the task finishes. That ties to INP (Interaction to Next Paint), one of the three Core Web Vitals; the others are LCP (Largest Contentful Paint, loading) and CLS (Cumulative Layout Shift, visual stability). web.dev describes these as primarily field metrics, measured on real users' devices.
Web Workers run scripts in background threads but cannot touch the DOM directly; they talk to the page by messages. The Event Loop and the Main Thread lesson covers splitting work up.
Shipping to devices that hold old copies
After a deployment, nobody's page changes by itself. A tab opened an hour ago keeps running the code it downloaded an hour ago, and caches may keep files longer.
MDN's HTTP caching guide describes the standard approach: put a version or hash in the file name and send a long lifetime, so a new build gets a new URL and nothing stale is reused. The HTML document cannot have a changing name, so it is sent so the browser revalidates it. The two cases look like this.
Cache-Control: no-cache
For the HTML document: the browser may store it but must check with the server before reusing it.
Cache-Control: public, max-age=31536000, immutable
For a hashed file such as /assets/app.3f9a1c.js: keep it for a year (31,536,000 seconds) and do not revalidate on reload.
That fixes the files, not the open tab. Old code in that tab can request a file the new deployment no longer serves, or send a request in a shape the new API rejects.
Figure 4. An open tab that outlives a deployment.
still running version 1 T->>H: request a version 1 file it needs now H-->>T: 404 not found Note over T: the load fails and
the feature breaks
How to read this: the failure happens long after the deployment, in a tab it never touched. A front-end release process must plan for the period when two versions are live.
Service workers add a related case: MDN says a newly installed version waits while the old one keeps controlling open pages. Any layer that caches your code can keep an old version alive.
What you cannot see unless you send it
On the back end you see requests in your logs. On the front end, an exception on a shopper's phone is invisible unless the page reports it. A small reporter is the first piece of observability.
function report(kind, detail) {
const body = JSON.stringify({
kind,
detail,
page: location.pathname,
release: "2026-11-07.1", // illustrative build identifier
});
// Queues a small POST; true means queued, not received.
return navigator.sendBeacon("/telemetry/errors", body);
}
window.addEventListener("error", (event) => {
report("error", { message: event.message, file: event.filename, line: event.lineno });
});
window.addEventListener("unhandledrejection", (event) => {
report("rejection", { reason: String(event.reason) });
});
error fires when a script throws and nothing catches it; unhandledrejection fires when a promise is rejected and nothing handles it. MDN describes navigator.sendBeacon() as an asynchronous POST for analytics and diagnostics, limited to about 64 KiB of queued data. The release identifier tells you which version produced an error, which matters when two versions are live.
How this course is organised
This is the first lesson of the Frontend System Design course. The first course covers the foundations: how a browser turns bytes into pixels, how the single thread schedules work, how HTTP caching behaves, how rendering strategies compare, how loading performance is measured, and how to turn users, devices and networks into requirements. Its lessons are How a Browser Actually Works, The Critical Rendering Path, The Event Loop and the Main Thread, HTTP Caching for the Front End, Rendering Strategies, Loading Performance and Core Web Vitals, and Frontend Requirements: Users, Devices and Networks.
Figure 5. The planned shape of the Frontend System Design series.
Browser, rendering
and performance"] --> B["Planned
React and state"] B --> C["Planned
Data and APIs"] C --> D["Planned
Security"] D --> E["Planned
Large-scale and
enterprise"] E --> F["Planned
Case studies"]
How to read this: only the first box exists today. The later boxes are plans, and their order and content may change.
How it connects to the back-end System Design course
The front end and back end meet at HTTP. This course links to the back-end lessons instead of repeating them.
| When you are thinking about... | Read this back-end lesson |
|---|---|
| The whole system and the three questions every design starts with | System Design: The Big Picture |
| What happens to a request after the browser sends it | Request lifecycle |
| Cache layers, TTLs and invalidation | Caching basics |
| Serving static files near users | CDN and object storage |
| The shape of the APIs the front end calls | API design |
| Turning a vague brief into measurable goals | Requirements |
The habit is the same on both sides: start from requirements, name the trade-off, measure the result.
In practice: redesigning an online store's product page and checkout
A realistic scenario, not a case history. This is a composite example built from common patterns. It does not describe any real company, and every detail in it is an illustrative assumption.
The situation
An online store has a product page and a three-step checkout, built as one client-rendered single-page application. Five front-end engineers own it; a separate team owns the catalogue and checkout APIs. Product managers report lower conversion on phones than on laptops, and support tickets mention a blank screen while the page loads. The page also loads two third-party scripts (analytics and a chat widget) that the team does not control. There are no front-end error reports and no real-user performance data; the team tests on an office laptop.
Starting architecture
Figure 6. The starting point: one client-rendered application and two third-party scripts.
How to read this: the shopper sees nothing meaningful until the bundle has downloaded and run and the product data has returned. The third-party scripts compete for the same main thread.
Options considered
| Option | What it fixes | What it costs | Risk |
|---|---|---|---|
| Keep the application and trim the bundle | Download and run time | Code-splitting effort | Smaller gain: the page still waits for data after the code runs |
| Build product-page HTML on a server or ahead of time; keep checkout client-rendered | First view of product pages | A rendering server or build step; two rendering modes | More moving parts; caching and personalisation rules must be right |
| Rewrite on a new framework | Possibly everything | Months of work | High: a long period with no user benefit |
The decision
| Field | Decision record |
|---|---|
| Context | Product pages are the entry point and are mostly the same for every shopper; checkout is personal and interactive. Nobody can say how the page performs on real phones. |
| Decision | Add field measurement and error reporting first. Then render product pages ahead of time or on a server, split code so checkout loads only when needed, and check a performance budget in the build. Keep checkout client-rendered. |
| Consequences, good | The first view no longer waits for the whole application; regressions are caught before release. |
| Consequences, bad | Two rendering paths to maintain; price and stock on a pre-built page can be stale unless refetched in the browser. |
| Revisit when | Field data meets its goals for several weeks, or stale-price complaints pass an agreed level. |
Measurement comes first on purpose: without field data the team would be choosing between options based on a laptop.
Rollout and verification
Stage one ships the error reporter above, with a release identifier, plus Core Web Vitals collection in production, to get a baseline. Stage two adds the budget to the build. Stage three releases the new product page behind a flag to a small share of visitors and compares the two groups on LCP, INP, CLS, error rate and checkout completion. The flag widens only while the numbers hold; turning it off is the rollback.
The 2 a.m. failure
A late release publishes a new build and, in its cleanup step, deletes the previous build's files. Shoppers who opened checkout before the release tap "Continue". The old code requests a step file that no longer exists, the host answers 404, and the dynamic import() in the old code rejects (MDN says it does so when the module fetch fails), so the step never appears. This is Figure 4.
Detection: the reporter shows a spike of rejection events tagged with the previous release, and checkout completion drops while the new release's numbers look normal. First checks: the release tag on the failing reports, the failing URL (a hashed file from the old build) and the cleanup step in the deployment log. Mitigation: restore the old build's files, which fixes open tabs at once. Follow-up: keep old files longer than a typical session, catch import failures and ask the shopper to reload, and add the rule to the release checklist.
Architect's notes
- Measure before you choose. Real-user data tells you whether the problem is code size, waiting for data or third-party scripts.
- Decide early: the rendering approach per page type, where each kind of state lives, the performance budget and how old tabs are handled. These are costly to change later.
- Design for the slowest device and network you support, and test there.
- Treat third-party scripts as dependencies. They run on your main thread and can fail; name an owner for each.
- Keep the trust line clear. The browser improves the experience; the server enforces the rules.
Common mistakes
- Treating the front end as only the UI layer. Delivery, caching and observability often explain the problem.
- Judging performance on a developer laptop. Use field data from real devices.
- Assuming one version of the code is live. Old tabs and cached files keep running after a release.
- Trusting the client. Browser validation is for experience; the server must check again.
Key takeaways
- A front-end system is everything between the device and the back end: code, network, delivery and the practices that keep it healthy.
- The runtime is a device you do not control, so design for the slowest and oldest devices you intend to support.
- One main thread runs most of your code and handles input; long tasks make a page feel broken.
- A release does not replace what users already have, so two versions can be live at once.
- State is both shared and per tab; deciding where each piece lives is a design decision.
- The eight decisions: rendering strategy, data fetching and caching, state ownership, code shipping, performance budget, accessibility, security boundary, observability.
- Measure in the field, because you cannot see the device unless the page tells you.
Practice exercises
Exercise 1 - Starter (20 min): Pick a site you use daily. Describe what happens between your device and its back end when you open its home page, using the five layers of Figure 2 as headings. Mark any layer you cannot describe.
Exercise 2 - Intermediate (1 hour): In your browser's developer tools, open the network panel on a product or article page. Group the downloaded files by the layer whose decision produced them, then find the caching headers on three files and judge them against the MDN caching guide.
Exercise 3 - Intermediate (2 hours): Add the error reporter to a small page with a /telemetry/errors endpoint that logs the body. Trigger a thrown error and a rejected promise and confirm both arrive.
Exercise 4 - Advanced (half day): Write a one-page decision record for the store assuming most shoppers are on slow networks. Choose an option, justify it, and list three measurements to collect before and after.
Related reading
In this course:
- Frontend Requirements: Users, Devices and Networks — turning wishes into testable requirements and a budget.
- How a Browser Actually Works — the processes and threads inside a browser, and the path of a navigation.
- The Critical Rendering Path — how bytes become pixels, and what blocks what.
- The Event Loop and the Main Thread — how work is scheduled on the one main thread.
- HTTP Caching for the Front End — which responses the browser keeps, and for how long.
- Rendering Strategies: CSR, SSR, SSG, ISR and Streaming — where and when HTML is produced.
- Loading Performance and Core Web Vitals — how to measure loading, interaction and stability.
Elsewhere on the site:
- System Design: The Big Picture - the back-end counterpart to this lesson.
- System Design: Request Lifecycle - what happens after the browser sends a request.
- System Design: Caching Basics - cache layers, TTLs and invalidation.
- System Design: CDN and Object Storage - serving static files near users.
- System Design: API Design - the contract the front end depends on.
- System Design: Requirements - turning a brief into measurable goals.
Official documentation
- web.dev: Baseline - how browser support is described and what "widely available" means.
- web.dev: Rendering on the Web - client-side, server-side and static rendering and their trade-offs.
- web.dev: Web Vitals - LCP, INP and CLS, and why they are field metrics.
- web.dev: Optimize long tasks - the main thread and the 50 millisecond definition.
- MDN: HTTP caching - versioned URLs,
no-cacheandimmutable. - MDN: Using Web Workers - background threads and the no-DOM rule.