# We Built the Frontend First and the Database Last

- **Category:** Process
- **Date:** 2026-08-14
- **Updated:** 2026-10-12
- **Read time:** 7 min

Most software is built in one order: model the data, write the migrations, expose an API over the tables, then have the frontend render whatever comes back. By the time the API exists, most of what users will see is already decided. Field names become labels, table boundaries become tabs, nesting becomes layout, and a migration's enum becomes the words in a status chip. None of it was reviewed as a product decision, because it looked like schema. The person with the least visibility into how the product feels ends up with the most influence over it.

## The order we used instead

In a generalized example, an operator-facing dashboard is built against fixture data before a durable backend. Client identities and implementation details are omitted. A few local route handlers existed, but they read from the same fixtures and touched no database. The output that mattered was a types directory capturing the shapes the screens actually needed. Only then was the platform repository created: the prototype became the frontend, and the contract library, the service, and the database schema were derived from what the UI had settled. The schema landed last. The screens were the requirements document.

## Why the screen is the better source of truth

A table answers "how should this be stored." A screen answers "what does a person need to decide something." One status indicator ended up with three states named for the three situations an operator needed to tell apart. Backend-first, that would have been a raw timestamp with each screen deciding what counted as stale, producing three definitions of the same word. Instead the state is the contract: the service computes it once and every surface reads the same value.

## Why this is newly practical

Backend-first won on economics: reshaping an API meant a ticket, a sprint boundary, sometimes a migration. The cheap local fix was for the frontend to absorb the mismatch, which is why so many codebases carry a 400-line transformers.ts mapping API responses onto component needs. Conforming a backend to a settled contract is mechanical, well-specified work that Claude does well, so that cost has dropped. In that frontend there is no transformers.ts, no adapters, no mappers, no normalizers, because nothing needed transforming.

## Where it breaks

The UI does not define physics: a field requiring a ten-million-row scan is a real constraint, and the negotiation still happens, just opened from the user's side. Authority is never view-driven: ownership is derived from the authenticated caller regardless of what the form submits. One screen's shape is not an API: when the same status appeared in two places and could disagree, the fix went into a shared read model, not into each screen. View-shaped endpoints over a stable domain layer, not view-shaped tables. And storage is still modeled properly; the API conforms, the normalized schema underneath does not.

## The method

Build the screen first against plausible fixture data. Extract the shapes the screens need into their own module and treat it as the contract. Hand that contract plus your existing data to Claude to write the layer in between, letting mismatches surface in the backend where they are cheap rather than in components where they become permanent. The order you build in decides who holds the pen.
