The Walking Skeleton
Browser → API → Database → Browser, doing almost nothing, working end to end, deployed. A walking skeleton is the thinnest possible slice built to prove the pieces connect — and it deliberately proves nothing else.
The situation, the reflex, and why it stalls
Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.
Before any feature is built, what is the smallest thing that would prove every part of the system can talk to every other part?
Day one of the store. You have a decomposition, a first slice in mind, and a fresh repository. You could start on the product page — but you also do not yet know whether the framework talks to the database, whether the deployment works, or whether the API and the page even run in the same place.
Set up the project properly. Install the framework, configure the database client, set up linting and tests, write the models, get the folder structure right. Then features will go quickly, because the scaffolding is solid.
The scaffolding is configured against no feature, so its correctness is unknown until a feature runs — and the first feature discovers the database URL is wrong in production, the API and page are on different origins, and the test runner cannot see the database.
- The scaffolding is configured against no feature, so its correctness is unknown until a feature runs — and the first feature discovers the database URL is wrong in production, the API and page are on different origins, and the test runner cannot see the database.
- Setup expands without a stopping rule. Auth scaffolding, an ORM, a component library, CI — all reasonable, none proven, each one another thing that could be the reason the first feature fails.
- The first feature becomes the first integration test of the entire environment as well as of itself, so when it fails nobody knows whether the feature or the environment is at fault.
The move
Precisely enough to apply it to a problem you have never seen — not a slogan.
- Build the thinnest path through every layer that will exist, with the least possible content, and get it running where it will run. A page that calls an endpoint that reads one row from the database and shows it. Nothing configurable, nothing reusable, nothing pretty.
- Include every boundary the real system will cross — browser to server, server to database, and the deployment — and exclude every feature. The skeleton is about connections, not capabilities.
- Deploy it. A skeleton that only walks on a laptop has not proved the boundary that fails most often. If deployment is a week away, the skeleton is not done.
- Then grow features onto it slice by slice (Vertical Slices). Every later slice inherits a proven path and only has to prove itself.
The skeleton as a slice
The thinnest slice there is, written in the slice device. Each layer does the least thing that constitutes crossing it. The required last line is longer than usual, because a skeleton proves almost nothing on purpose.
- BrowserLoads one page, fetches one route, prints one string.
- APIOne route that runs one query and returns one field.
- DatabaseOne table, one row inserted by hand.
- Browser againReceives the response and shows it; that is the whole observation.
- DeploymentThe same path, in the environment where the store will live.
Every boundary, once
The skeleton's content is arbitrary; its shape is not. It must cross every boundary the real system will have. The diagram is the store's; the chat app's would add a persistent connection, and the file-upload service's would add object storage.
Building it, and stopping
The skeleton is short enough to be a pipeline with a hard stop. The failure column is mostly one failure: not stopping.
- 1List the boundaries
Browser–server, server–database, deployment; plus any external system already known to be in V1.
fails by Listing features instead of boundaries.
- 2Choose the least content
One row, one field, one route, one page.
fails by "While I am here" — a real product model, a component library.
- 3Cross each boundary once
Write the least code that makes the request travel the whole path.
fails by Adding auth, validation or error handling; each is a feature, not a connection.
- 4Deploy
Run the same path where the system will live.
fails by Declaring it done on a laptop; the environment boundary is the one that fails most.
- 5Stop
Write down what was skipped; hand the proven path to the first slice.
fails by Growing the skeleton into the MVP without ever choosing a slice.
How to do it
Most important first.
- List the layers and boundaries the system will have: browser, API, logic, database, and anything external you already know about. The skeleton must touch each once.
- Choose the content to be the least that can be observed: one row, one field, one route, one page with one value on it.
- Skip everything that is not a connection: no auth, no validation, no styling, no error handling beyond the framework default. Write each skip down.
- Run it in the real environment before calling it done (Short Feedback Loops).
- Keep it: the skeleton's route becomes the health check, or the first product slice replaces it directly.
Worked on a concrete problem
The move has to produce something. This is what it produced.
- The store's skeleton: a products table with one row inserted by hand;
GET /products/1returning it as JSON; a page that fetches that route and prints the name; deployed to wherever the store will live. Four hours including the deployment, which found that the production database needed a different connection string — a discovery worth exactly four hours and not four weeks. - What it proved: the framework serves pages and API routes together; the database is reachable from the server in both environments; the page can call the API from the browser (so cross-origin is settled); deployment works. What it did not prove: anything about products, carts, checkout, auth, or how the system behaves with real data or real users.
- The chat app's skeleton, for contrast: one message inserted by hand; a websocket that pushes it to a connected browser; the browser shows it. The extra boundary — the persistent connection — is in the skeleton because it is the one most likely to fail in deployment, and the skeleton's job is to cross every boundary once.
How you know it worked
What now exists that did not before, and what question you can now ask.
- A URL exists, in the real environment, that shows a value that came from a database row.
- You can name every boundary the skeleton crossed, and every one the real system will have is on the list.
- The first feature slice was smaller than expected, because the path was already open.
The questions you can now ask
The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.
- ?Which boundaries will this system cross, and has each been crossed once, with the least possible content?
- ?Does the skeleton run where the system will run — and if not, what is stopping it?
- ?What did I skip to keep it thin, and is each skip written down?
- ?What is the first real slice to grow onto it?
What can go wrong
- The skeleton grows flesh: "while I am here" adds auth, a component library and an ORM, and the skeleton becomes the scaffolding it was meant to replace, unproven by any feature.
- The skeleton skips a boundary — usually deployment or the real database — and proves connectivity only in the environment that was never in doubt.
- Mistaking the skeleton for the first slice. It shows a hard-coded row; it is not "show one product" until the row is real and the id comes from the user. Both are valid; confusing them means the first feature is never actually built.
- The skeleton is throwaway-shaped — a hard-coded row, a page that prints a string — and it is tempting to skip it because nothing in it survives. What survives is the proven path, which is not visible in the code.
- Deploying on day one costs the deployment setup on day one, before anyone has asked for a deployment.
- "The skeleton is the MVP." An MVP proves the idea to a user; a skeleton proves the connections to the builder. The skeleton shows nothing a user would want (MVP Thinking).
- "Set up everything properly first, then the skeleton." The skeleton *is* the setup, tested. Setting up more than the skeleton needs is scaffolding against imagined needs, which is the reflex.
Where this applies
Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.
- STAGE-SPECIFICOn a greenfield system the skeleton is the first thing built; in an existing system the skeleton already exists and the move becomes finding the thinnest path through it that touches every layer a new feature needs — the same idea, applied to a change rather than a system.
- GENERALCrossing every boundary once with minimal content applies to any system with boundaries — a CLI that reads a file and writes one, a pipeline that ingests one record and emits one row.
- ILLUSTRATIVEThe four hours, the connection string and the chat app's websocket are invented for the example; the boundaries a real system crosses are its own.
Where the depth lives
This domain asks the question and hands the answer off by name.