Front End Lesson 3 – Web Architecture Overview | Dataplexa
Front End Engineering · Lesson 3

Web Architecture Overview

Map the full journey of a web request — from URL bar to painted pixels — and understand where front end engineering lives inside that pipeline.

The Distance Between Click and Content

When Stripe's infrastructure team redesigned their checkout architecture in 2022, page load time dropped by 340 milliseconds. No visible design change. No new features. Pure architecture. That 340ms translated directly into measurable conversion improvement — because users weren't waiting as long between clicking "Pay" and seeing the confirmation screen.

Most developers treat the browser as the starting line. It isn't. By the time the browser gets involved, several distributed systems have already negotiated behind the scenes. Understanding that negotiation is what separates engineers who fix symptoms from those who fix causes.

The Full Journey of a Web Request

1
DNS Resolution — The domain name (e.g. app.pixelforge.io) is translated into an IP address by a distributed network of servers. This step alone can add 20–120ms on a cold lookup.
2
TCP Handshake + TLS Negotiation — The browser and server establish a secure connection. Three packets travel back and forth before a single byte of actual content is sent.
3
HTTP Request → Server — The browser sends a GET request. That request may hit a CDN edge node, a load balancer, an API gateway, and finally an origin server — or some combination of all of them.
4
Server Response — The server returns HTML (or JSON, or a redirect). The response carries cache headers, compression settings, and CORS rules that the front end will encounter milliseconds later.
5
Parse → Render → Paint — The browser processes the HTML, fetches linked CSS and JS, builds internal trees, runs layout calculations, and finally paints pixels. This is where front end engineering lives — but everything before this point shapes how quickly this step can start.
6
Interactive — JavaScript executes, event listeners attach, and the page becomes usable. The gap between "painted" and "interactive" is where many slow pages hide their real problem.

The PixelForge Performance team discovered this directly. Their dashboard felt slow even after optimising React component renders. The real culprit was a 180ms DNS lookup on a third-party font provider — a step happening before the browser had even received a byte of HTML. Fixing it required understanding the full stack, not just the JavaScript layer.

Three Layers, One System

Web architecture is usually described as "client–server." That framing is accurate but dangerously simple. In any production web application today, there are at least three distinct layers that every request passes through — and each layer has a different job, different failure modes, and different performance levers.

Client Layer

The browser — or native app shell. Responsible for rendering HTML, executing JS, and managing user interaction. Front end engineers own this layer entirely. Performance here is measured in paint times, input latency, and bundle sizes.

Edge / CDN Layer

Distributed servers placed geographically close to users. They cache static assets (JS bundles, images, fonts) and increasingly run compute too — Vercel's Edge Functions, Cloudflare Workers, and AWS Lambda@Edge execute code at 200+ global points of presence.

Origin / API Layer

The authoritative server — a Node.js app, a Rails service, a Go microservice, or a serverless function. It owns the database connection, business logic, and authentication. Round-trip time here is the floor of your application's data-fetching speed.

The Glue Between Layers

HTTP headers, cache-control directives, CORS policies, and service workers are the connective tissue. A misconfigured Cache-Control header can mean your CDN serves stale data for 24 hours. A missing CORS header can silently block API calls in production.

Front end engineers interact with all three layers — even if they never write a line of backend code. You decide which API endpoints to call and when. You configure how assets are cached. You write service workers that intercept network requests. Treating the front end as isolated from the network layer is a mindset that produces slow, brittle applications.

Rendering Models — The Most Important Decision in Your Architecture

GitHub's engineering blog published a postmortem in 2021 about a failed migration from server-rendered ERB templates to a fully client-side React SPA. The result was a regression in Time to Interactive from 1.8s to 4.1s on median hardware. They rebuilt using a hybrid model that kept HTML delivery server-side and handed JS execution only to the interactive parts. Performance recovered to 1.4s — better than the original. The choice of rendering model had a larger impact than any individual component optimisation.

There are four primary rendering models in production use today. Every new project forces a choice between them — and that choice cascades into bundle strategy, caching strategy, SEO posture, and developer experience.

Rendering Model How It Works First Paint Speed Best For
CSR — Client-Side Rendering Server sends a near-empty HTML shell. Browser downloads JS bundle, executes it, and the framework renders everything in the browser. Slowest — user stares at blank screen while JS loads Dashboards, authenticated apps, internal tools
SSR — Server-Side Rendering Server generates complete HTML per request. Browser receives readable content immediately. JS then "hydrates" — attaches interactivity to existing HTML. Fast first paint — but server must respond before anything renders Content sites, e-commerce, SEO-critical pages
SSG — Static Site Generation HTML is pre-built at deploy time. The CDN serves static files — no server needed per request. Fastest possible delivery. Fastest — CDN edge serves pre-built HTML instantly Marketing sites, docs, blogs, pages that rarely change
ISR — Incremental Static Regeneration Pages are statically generated but can be regenerated in the background after a set interval. Stale content is served while fresh content is built — no visible rebuild delay. CDN-fast with freshness guarantees E-commerce product pages, news articles, hybrid apps

The Hydration Tax

SSR and ISR both involve a step called hydration — where the browser downloads the same JS the server already used, re-runs it, and attaches event listeners to the pre-rendered HTML. This costs time and CPU. A large Next.js app can spend 2–3 seconds on hydration alone on a mid-range Android device. Frameworks like Astro (with islands architecture) and Qwik (resumability) are trying to eliminate or defer this cost entirely.

The PixelForge Platform team ships two separate rendering models simultaneously. The marketing site (pixelforge.io) uses SSG through Next.js — it rebuilds on every deploy and individual pages revalidate hourly via ISR. The web application (app.pixelforge.io) is CSR-only, since it's fully authenticated and SEO is irrelevant behind a login wall.

CDNs — The Layer Most Developers Underestimate

A Content Delivery Network is a geographically distributed cache. Instead of every request crossing an ocean to reach a server in Virginia, a user in Mumbai hits a CDN edge node 8 milliseconds away. That single architectural decision — moving assets closer to users — is responsible for more web performance improvement than any front end optimisation technique combined.

Cloudflare operates over 285 edge locations. Fastly reaches 93% of internet users within 50ms. When Shopify serves 1.7 million merchants globally, every static asset — every JS chunk, every CSS file, every product image — routes through their CDN layer. The origin server barely touches those requests.

CDN Cache HIT

User requests main.abc123.js. The CDN edge node already has it. Response time: 8–30ms. Origin server is never contacted. This is the ideal scenario for any static asset.

Response header: X-Cache: HIT

CDN Cache MISS

User requests a newly deployed bundle. Edge node has nothing. It fetches from origin, caches the response, and returns it. First user pays the full round-trip cost. Every subsequent user gets the cached version.

Response header: X-Cache: MISS

Front end engineers control CDN behaviour through Cache-Control headers. A JS bundle with a content-hash in its filename (e.g. chunk.a8f3d2.js) can be cached for one year: Cache-Control: public, max-age=31536000, immutable. The hash changes with every build, so browsers and CDNs fetch the new file automatically. An HTML file, by contrast, should never be cached long-term — it's the pointer to all those hashed assets.

The Cache Invalidation Trap

Phil Karlton famously said there are only two hard problems in computer science: cache invalidation and naming things. If you deploy a bug fix but your HTML has a long max-age, users keep receiving the broken version from their browser cache. Always use content-hashed filenames for JS and CSS, and keep HTML cache duration short (or zero).

APIs — How the Front End Talks to Everything Else

The front end never stores the real data. User profiles, project files, collaboration state — all of it lives in databases the browser can't directly touch. Every interaction that needs real data goes through an API: a defined contract between the client and the server. How that contract is designed has enormous consequences for how fast, how reliable, and how complex your front end becomes.

API Style Data Shape Over-fetching Risk Type Safety PixelForge Team Uses
REST Fixed endpoints return fixed shapes — GET /projects returns every field whether the UI needs it or not High Requires OpenAPI + codegen Platform team — public API for integrations
GraphQL Client asks exactly for what it needs — queries declare field requirements at call time Low Schema-first, codegen available Design Systems — component data needs vary per view
tRPC TypeScript functions on the server become callable on the client — no separate contract definition needed Low Native end-to-end TypeScript Frontend team — internal dashboard features ship faster with full-stack type safety

Over-fetching is a problem REST developers often accept as normal. A GET /users/42 endpoint might return 47 fields when the UI only needs 3. On mobile over a 4G connection, those extra fields cost real bytes and real milliseconds. Linear solved this by building a tight GraphQL API where every client query is specific — their mobile app downloads precisely what it renders, nothing more.

Monolith vs Micro-Frontend — When to Split the Front End Itself

Atlassian hit a wall around 2018. Their Jira and Confluence front ends had become enormous single applications — millions of lines of JavaScript shared across teams that had entirely different release cycles and different product priorities. A bug fix in one team's component required coordinating deploys with four other teams. Their solution was to split the front end the same way backend teams split services: micro-frontends.

A micro-frontend is an architectural approach where the front end is divided into independently deployable slices — each owned by a separate team, each shippable without touching the others. The shell application composes them at runtime using module federation, iframes, or web components.

Monolithic Front End

One codebase, one build, one deploy. Simple to start. Every engineer works in the same repo. Bundle optimisation is easy because you see everything at once.

Pain point: At 20+ engineers, merge conflicts multiply. A single broken test blocks every team's deploy pipeline.

PixelForge started here. Still works for early-stage products.

Micro-Frontend

Each product slice is a separate package. Teams deploy independently. A bug in the Comments feature doesn't block the Canvas team from shipping.

Pain point: Bundle duplication is real — each slice may ship its own copy of React unless you use shared module federation. Debugging across slice boundaries is harder.

Where PixelForge is heading as the Platform and Design Systems teams scale separately.

The right choice depends on team size, not application size. A 5-person team building a complex product does not need micro-frontends. A 50-person team with four independent product squads absolutely does. Introducing micro-frontend complexity at the wrong time creates overhead without benefit.

Module Federation

Webpack 5 introduced Module Federation — a mechanism for one JavaScript application to dynamically load code from another at runtime. Each micro-frontend exposes components as a remote. The shell application consumes them without bundling them at build time. This means the Comments team can deploy a new version of their component and every user on the platform gets it instantly — without a full app rebuild. Vite has a community plugin for this too: vite-plugin-federation.

Where Architecture Decisions Actually Live

Architecture isn't a document you write once. Every pull request is an architecture decision — whether you treat it that way or not. A developer who adds a new useEffect to fetch data in a component has made an architecture decision about where data lives. One who imports a 120KB library to format a date has made a performance architecture decision that will affect every user on a slow network.

Senior front end engineers develop an architectural instinct — the ability to see the second and third-order consequences of a code change. Adding a new HTTP request inside a component render cycle can create N+1 network patterns. Storing server state in a global Redux store when you could use React Query doubles your data management complexity for zero benefit.

How One Architecture Decision Cascades

1
Team chooses CSR (React SPA) for PixelForge's editor because everyone knows React and it ships fast.
2
SEO becomes impossible for the marketing pages that live on the same domain — Googlebot sees blank HTML during the initial render cycle.
3
Marketing pages get split onto a subdomain with a separate Next.js SSG deployment — adding infrastructure and cross-domain authentication complexity.
4
Shared components now need to work across two different build systems — a design system package gets introduced to manage the duplication.
5
Three months later: five engineers are maintaining two apps, a shared component library, and a CDN routing config — all because of one early decision to keep things "simple."

None of those consequences are wrong — they're just real. The engineers who made those decisions weren't incompetent. They just didn't trace the cascade before committing. Architecture thinking is consequence thinking. And the best time to think about consequences is during the pull request discussion, not six months after the technical debt has accrued.

The PixelForge Architecture Decision Record (ADR) — a lightweight one-page document the Platform team writes before any major architectural change — asks three questions: What problem does this solve? What are the tradeoffs? What do we have to undo if this turns out to be wrong? That third question is the one most teams skip. And it's the one that matters most at 2am when something breaks in production.

Quiz

1. The PixelForge marketing site needs sub-100ms Time to First Byte globally and pages only change on product launches. Which rendering model fits this requirement best?

2. PixelForge deploys a bug fix but some users are still seeing the broken version hours later. What CDN caching strategy should the Platform team adopt to prevent this without sacrificing cache performance on assets?

3. PixelForge has grown to 60 engineers across four product squads. A broken test in the Comments feature is blocking deploys for the Canvas and Templates teams. What architectural change should the Platform team propose?

Up Next
Browser Rendering Pipeline
PixelForge's Performance team traces the exact sequence of steps from raw HTML bytes to painted pixels — and finds three places to cut 400ms from their dashboard load time.