skip to content

Your team keeps finding breakage only after deploying because everyone works against the development server — how would you change that?

level: seniorimportance: should knowfreq 46%

answer

  1. loop speed and fidelity are different modes
  2. build on every change, not per release
  3. one command to serve the build
  4. name the residue a local build misses

basics

~20 s

Verify against the built output: build on every change in the pipeline so every route is compiled and prerendered, and run the build locally before anything risky ships. Keep the development server for the edit loop.

solid answer

~50 s

Two moves, in that order. First, put the build in the pipeline on every change, not only before a release — that alone catches the coverage and environment failures, because the build compiles every route and runs on a clean machine. Second, give developers a one-command way to run the **built output** locally and make it the norm before shipping anything that touches data freshness, caching, prerendering or payload size; that is the only local mode where those behave as they will after deploy. Then be explicit about the residue: a local built run still is not the hosting target, and it has neither production data volumes nor real network latency, so a small set of issues still needs a deployed preview. Naming which classes each step catches stops the team from believing a green local build means more than it does.

go deeper

for a junior

The takeaway is that there is a second way to run the application locally — build it, then serve the build — and that it is the one to use before shipping something risky.

for a middle

Be able to say which bug classes each mode catches, and why a pipeline build is a coverage test: it compiles every route on a machine that only has the repository.

for a senior

Show the design: automated build on every change, a one-command local built run scoped to the changes that need it, and an explicit list of what still escapes both.

for a principal

Argue it as an investment with a measurable target — the share of incidents whose cause is a class the development server hides — and defend the decision not to buy the last increment of parity.

The pattern behind "it worked locally" is almost never carelessness. It is that the team's daily feedback loop runs in a mode that deliberately behaves differently from the deployed one. Fixing it means adding modes of verification, not adding discipline. ## Name what each mode can catch Before changing anything, make the gradient explicit. Each step costs more time and catches a strictly larger set. | Mode | Catches | Still cannot catch | |---|---|---| | Development server | Logic, markup, styling, data shape | Coverage of unvisited routes, caching, prerendering, payload | | Build, in the pipeline | Unvisited-route errors, missing files and configuration, casing | Anything about how a request is served | | Built output, run locally | Caching, reuse, prerendering, real payload sizes, startup behaviour | Hosting-target shape, real data volume, real latency | | Deployed preview | The above, on the real target | Production traffic patterns and scale | A table like this is worth writing down for the team, because the common failure is not skipping a step — it is believing a step proves more than it does. ## The two changes that do most of the work **Build on every change.** Move the build from "before a release" to "on every commit or pull request". It is the cheapest possible coverage test: the build compiles every route and executes the prerenderable ones, on a machine that only has what the repository carries. Coverage failures then land on the commit that caused them, while the author still has the change in their head. **Make running the built output a one-liner.** Two commands — build, then serve the build — behind a single task everyone knows. If running the build locally takes a wiki page, nobody will do it. Then set the expectation that it is run before merging any change that touches: - a data function's caching or revalidation behaviour, - whether a route is prerendered or rendered per request, - anything that changes what ships to the browser, - server-side module state or startup work. Those are exactly the categories the development server is structurally blind to. ## Be honest about the residue A local built run is a large improvement and still not the deployment. Three gaps remain, and each is better acknowledged than papered over: 1. **Shape of the target.** Whether the built output runs as a long-lived process, as per-request functions, on an edge runtime, or as files on a static host changes what is possible for it; a local run picks one shape and tells you nothing about the others. 2. **Data and traffic.** Local data sets are small, warm and uncontended. Anything that only breaks at volume, under concurrency, or with a cold cache will not appear. 3. **Network reality.** Latency, compression, a CDN in front, and real client devices are all absent. The honest conclusion is that some classes of bug can only be caught by a deployed preview, which is an argument for having one per change — not an argument against local parity. ## Make the fast mode honest rather than accurate One cheap move is worth more than it looks: teach the team the three differences — compiled on demand, rendered per request, caches bypassed — as a fact about the tool rather than folklore. A developer who can name why a page is always fresh locally stops treating that as evidence, which removes a whole category of mistaken confidence at no cost in loop speed. ## What not to do Two overcorrections are common and both cost more than they save: - **Making the built output the daily loop.** Developing against a build destroys the edit-to-see cycle the development server exists for. Parity is a gate you pass through, not a place you live. - **Adding process instead of automation.** A checklist item saying "remember to test the build" decays within a sprint. A pipeline step that fails the change does not. ## How you know it worked Pick a signal before you start and watch it: the share of production incidents whose root cause is a class the development server hides — a route nobody opened, a stale cache, a missing configuration value, a payload regression. If that share does not fall, the steps you added are catching something other than what was actually hurting you, and the gradient table is where you go to find out which step is missing.

  • Why is building in the pipeline on every change worth more than asking developers to build locally?
    Because it runs whether or not anyone remembers, on a clean machine that only has what the repository carries. That combination is precisely what catches missing files, absent configuration and wrong import casing — the failures a developer's own machine is least able to reveal.
  • Which problems still escape a locally run build?
    Anything determined by the hosting target's shape, by data volume and concurrency, or by the network between user and server. A local run picks one runtime shape, uses a small warm data set and has no latency, so those classes need a deployed preview rather than more local effort.
  • How do you keep the parity step from slowing the team down?
    Scope it. The build runs automatically in the pipeline for everyone; the local built run is expected only for changes that touch caching, prerendering, payload or server-side state. Everything else stays on the development server, which is where the speed comes from.

saying these in an interview costs you the question

  • Says the fix is for developers to be more careful
  • Treats a green local build as proof the deployment will behave
  • Proposes developing against the built output all day
  • Adds a checklist item instead of a pipeline step
  • Cannot name a single bug class that only a deployed run reveals