Anatomy of a modern app
Every web app is the same handful of parts — client, server, API, database, and the pipe from your repo to a live URL. Learn the map once and every framework slots into it.
Every web app you’ll ever build — or ask an AI to build — is the same three parts wearing different framework costumes: a client that renders UI, a server that owns logic and data access, and a database that persists state. The frameworks change; the map doesn’t. Learn the map once and “where does this code run?” stops being a mystery — and you can name each piece precisely enough to tell an AI exactly what to build.
Each tier has exactly one job, and the boundaries between them are where security and performance decisions live. The browser is public — anyone can read its code and lie to it. The server is trusted — it’s the only place that can hold a secret or decide what a user is allowed to do. The database is durable — it’s what survives a server restart. Confuse these and you get the two classic beginner bugs: a secret leaked into browser code, or a “security check” that only runs in the browser where any attacker can skip it.
Where does this code actually run?
The first question for any feature is which machine runs it — because that decides what it can do. Browser code is fast and interactive but public; server code is private and powerful but a round-trip away. The same language (JavaScript/TypeScript) can run in all four places, which is exactly why “where does this run?” is a real question and not an obvious one.
| Runs in | Good for | Can't do | Examples |
|---|---|---|---|
| Browser | interactivity, instant UI | keep secrets, trust its own input | clicks, form state, animations |
| Server | data access, secrets, logic | be instant for far-away users | API routes, DB queries, auth |
| Edge | fast reads near the user | heavy or long-running work | redirects, personalization, caching |
| Build time | work done once, not per request | anything user-specific | static pages, bundling |
One request, end to end
When you type a URL and hit enter, a fixed sequence runs. Knowing its rungs lets you say where something is slow or broken instead of “the site is down.” Each rung is a place a request can stall, fail, or be attacked — naming the rung is the first half of fixing it.
A page is “slow.” Where? The rungs turn that vague complaint into a checklist:
Slow DNS (rung 1) → first visit only; usually the registrar/DNS provider
Slow TLS (rung 2) → handshake/cert issue, often a misconfigured host
Slow server (rung 4) → your code: an unindexed query, a blocking loop
Slow DB (rung 5) → the query itself; the classic N+1 (Module 3)
Slow render (rung 7) → too much JS shipped to the browser (Module 5)The same trick works for failures: a 404 is the server (rung 4) saying “no such
route”; a 500 is your code throwing on rung 4–5; a blank page with a console error
is rung 7. Name the rung, then look there — don’t guess.
Repo, build, deploy — not the same thing
People say “ship it” as one word, but it’s a chain of five distinct stages. Naming them correctly is half of debugging a broken deploy — “the build failed” and “the deploy failed” point at completely different logs.
Why the frontend never talks to the database
An API is the single doorway between the public browser and your private data. The frontend asks the API for things (“give me this user’s orders”); the API decides whether that’s allowed, fetches the rows, and returns only what it should. If the browser could reach the database directly, every visitor would have your database password — and could read or delete anyone’s data. The API is where the trust boundary lives.
01 Learning objectives
0 / 6 done02 Curated reading
03 Knowledge check
- 01easy
How should the frontend get data out of the database?
- 02easy
Where does a secret API key belong?
- 03easy
“Build”, “deploy”, and “host” all mean the same thing.
- 04medium
Code that must keep a secret (e.g. a payment key) should run…
04 Interview questions
browse all ↗What gets asked on this topic — tap a card for how to approach it, the follow-ups, and the trap. Company tags are best-effort & sourced.
-
Name the three tiers of a typical web app and say what each is responsible for.
Three tiers: client/frontend (the browser — renders UI, handles interaction), server/backend (a machine you control — owns business logic, data access, and secrets), and database (persists state).
The key separation is trust: the browser is untrusted and public, so anything sensitive (DB credentials, API keys, authorization checks) lives on the server. The frontend asks the server for data; the server talks to the database.
Follow-ups they push on- Why can't the browser talk to the database directly?
- Where does an API sit in this picture?
Red flag Saying the frontend 'connects to the database' — it never does; it calls your server, which holds the credentials.
source: InterviewPrep — 3-Tier Architecture ↗ -
What is an API, in one sentence, and why does the frontend go through it instead of the database?
An API is a contract: a defined set of endpoints the server exposes so other code can request data or actions without knowing the internals.
The frontend goes through it because the API is the trust boundary. It can authenticate the caller, authorize the action, validate input, and hide DB credentials and schema. If the browser hit the DB directly, anyone could read its network traffic, steal the credentials, and run any query.
Follow-ups they push on- What does the API do that the database can't be trusted to do itself?
- What's the difference between an endpoint and a route?
Red flag Describing an API only as 'a URL' — the point is the contract and the trust boundary, not the address.
source: MDN — How does the web work? ↗ -
Trace what happens, end to end, when a user types a URL and hits Enter.
Walk the path out loud: browser parses the URL, DNS resolves the domain to an IP, the request reaches the host/server, the server/API runs logic and (if needed) queries the database, builds a response, sends it back, and the browser renders it.
Good signal is naming the layers in order and knowing DNS is a lookup, not the server itself. Bonus: mention HTTPS securing the connection along the way.
Follow-ups they push on- Where would caching help in that path?
- What's the difference between the host and the code running on it?
Red flag Skipping DNS, or thinking the domain name 'is' the server. DNS is the phone book that maps name to address.
source: MDN — How does the web work? ↗ -
What's the difference between 'build', 'deploy', and 'host'? People use them interchangeably.
They're three stages, not synonyms. Build compiles/bundles your source into shippable artifacts (the
dist/folder). Deploy is the act of pushing those built artifacts to a place that serves them. Host is the place itself — the always-on machine or platform serving the result.Mnemonic: build is a verb that produces files, deploy is a verb that moves them, host is the noun where they live.
Follow-ups they push on- Where does 'repo' and 'bundle' fit in the chain?
- What is CI/CD in one line?
Red flag Conflating build and deploy — you can build without deploying (a failed CI run) and redeploy the same build.
source: Vercel — Deployments overview ↗ -
What is an environment variable, and why should secrets never be committed to the repo?
An environment variable is config supplied to the program at runtime by its environment, not hardcoded in the source — things like the database URL or an API key. The same code reads different values in dev, preview, and prod.
Secrets stay out of the repo because git history is forever and repos get shared, cloned, and leaked. A committed key is compromised even after you 'delete' it — it's still in history. Secrets belong in the host's environment-variable/secret store.
Follow-ups they push on- You accidentally committed an API key. What do you do?
- Why use a `.env` file locally but not commit it?
Red flag Thinking deleting the line in a later commit fixes it — the secret is still in history and must be rotated.
source: The Twelve-Factor App — Config ↗ -
Where does your code actually run — client or server — and why does it matter for what you can put in it?
Client code is shipped to and runs in the user's browser — it's fully visible (anyone can open DevTools and read it) and editable, so it can keep no secrets and enforce no rules. Server code runs on a machine you control — invisible to the user — so it can hold credentials, reach the database, and enforce checks.
The practical rule: anything that must stay secret or be trusted (API keys, authorization, pricing, validation that counts) lives on the server. The client is for rendering and convenience-level checks only.
What a strong answer coversClient code runs in the user's browser — fully visible and editable, keeps no secrets.
Server code runs on a machine you control — invisible to the user, can hold credentials and enforce rules.
Secrets and trusted checks (auth, pricing, real validation) must be server-side.
Client-side checks are a UX nicety; the server must re-validate everything that matters.
Quick self-checkYou hardcode a third-party API key into your React component so the browser can call the API. What's the problem?
-
Wrong — compiled/bundled JS still ships to the browser and is readable in DevTools.
-
Correct — client code is fully visible; secrets belong on the server, which proxies the call.
-
Wrong — it works in both, which is exactly why it's dangerous; it leaks everywhere.
-
Wrong — that's not a real constraint; the issue is exposure, not length.
Follow-ups they push on- If you bundle an API key into your frontend JS, who can see it?
- Why is a 'disable the button' check in the browser not real security?
Red flag Putting an API key or secret in frontend code 'because it's just JavaScript' — it ships to every visitor and is trivially readable.
source: MDN — Server-side vs client-side code ↗ -
What's the difference between an endpoint and a route?
A route is the path pattern the server matches against an incoming request (
/users/:id). An endpoint is a specific addressable operation — usually a method + path together (GET /users/:idvsDELETE /users/:id) — that does one thing.In practice people use them loosely, but the useful distinction is: one route (path) can host several endpoints, one per HTTP method. The route is where the request lands; the endpoint is the exact action it triggers.
What a strong answer coversA route is the URL path pattern the server matches (
/users/:id).An endpoint is method + path together — a specific operation (
GET /users/:id).One route can back several endpoints, one per HTTP method (GET/POST/DELETE…).
:idis a path parameter — a placeholder filled by the actual request.
Follow-ups they push on- How does the same path serve a GET and a DELETE differently?
- What's a path parameter vs a query parameter?
Red flag Thinking a path alone fully identifies an operation — `/users/1` means nothing until you also know the method (read it? delete it?).
source: MDN — Routing (Server-side first steps) ↗ -
Why can't the browser talk to the database directly — what would go wrong?
To connect to a database you need its address and credentials, and the browser is a public, untrusted environment — anyone can read the page's network traffic and JavaScript. Shipping DB credentials to the browser means handing them to every visitor.
Even if you could, there'd be no enforcement layer: the database just runs whatever query it's given. The server sits in between precisely to authenticate the caller, authorize the action, validate input, and only then run a safe, scoped query. The DB stays on a private network the browser can't reach.
What a strong answer coversConnecting needs credentials; the browser is public, so those credentials would leak to everyone.
The database has no notion of *who* is asking — it just runs the query it's given.
The server is the enforcement layer: authenticate, authorize, validate, then query.
In real setups the DB lives on a private network the browser literally can't reach.
Follow-ups they push on- What does the server add that the database can't enforce itself?
- How is a DB connection string like an API key?
Red flag Imagining the database can 'just check permissions' itself — it executes queries; the trust/permission logic lives in your server code.
source: MDN — Server-side programming: first steps ↗ -
What's the difference between a request and a response, and what do status codes like 200, 404, and 500 tell you?
A request is what the client sends (method, URL, headers, optional body); a response is what the server sends back (a status code, headers, and usually a body). Every HTTP exchange is one request and one response.
Status codes are the response's one-glance summary: 2xx = success (200 OK), 3xx = redirect, 4xx = the client did something wrong (404 not found, 401/403 auth problems, 400 bad input), 5xx = the server broke (500 internal error). The first digit tells you whose 'fault' it is — 4xx is on the caller, 5xx is on the server.
What a strong answer coversRequest = client → server (method, URL, headers, body); response = server → client (status, headers, body).
2xx success, 3xx redirect, 4xx client error, 5xx server error.
404 = not found, 401/403 = not authenticated/authorized, 400 = bad request, 500 = server crashed.
The leading digit tells you where to look first: 4xx → the request; 5xx → the server logs.
Quick self-checkYour API returns 500 for a request. Where do you look first?
-
Wrong — that's the 4xx family; invalid input is a 400/422.
-
Correct — 5xx is the server's fault, so the stack trace/server logs are the place to start.
-
Wrong — DNS failure happens before any HTTP status is returned.
-
Wrong — 2xx is success; 500 is a server error.
Follow-ups they push on- If you see a 401 vs a 403, what's the difference?
- Why is a 500 your problem but a 404 might be the caller's?
Red flag Returning 200 for everything (including errors) and signalling failure only in the body — it breaks clients, caches, and monitoring that rely on the status code.
source: MDN — HTTP response status codes ↗ -
What is a runtime (Node, a browser, an edge runtime), and why does 'where it runs' change what your code can do?
A runtime is the environment that executes your code and decides which capabilities (APIs) are available. The same JavaScript behaves differently depending on the runtime: a browser runtime gives you the DOM,
fetch, andlocalStoragebut no filesystem; Node.js gives you the filesystem, network sockets, and process access but no DOM; an edge runtime is a stripped-down server runtime optimized to run close to users, often missing some Node APIs.So 'where it runs' is really 'which runtime', and the runtime is what gates what's possible —
fs.readFileworks in Node and crashes in a browser;document.querySelectorworks in a browser and is undefined in Node.What a strong answer coversA runtime is the execution environment that supplies the available APIs.
Browser: DOM,
fetch,localStorage; no filesystem or process access.Node.js: filesystem, sockets, env/process; no DOM.
Edge runtimes are lean server runtimes near the user — fast, but a subset of Node's APIs.
Follow-ups they push on- Why does `document` exist in the browser but not in Node?
- Why might a library work locally (Node) but fail when deployed to an edge runtime?
Red flag Assuming 'it's all JavaScript' means any code runs anywhere — runtime-specific APIs (fs, DOM) make code break when moved to the wrong environment.
source: MDN — JavaScript execution environments ↗