How Do Indie Hackers Ship an MVP API Fast?
For Solo indie hackers building MVPs · Based on Traversy Media Node/Express REST API Builder
// TL;DR
If you're an indie hacker building an MVP and need a backend API that's fast to scaffold but clean enough to scale, this skill is your playbook. It gives you a repeatable 12-step workflow for building a CRUD REST API with Node.js and Express, using route/controller separation that survives beyond launch day. Start with an in-memory mock array for speed, then swap in PostgreSQL when you're ready to persist data. Every endpoint is testable via Postman before you wire up your frontend.
Why should indie hackers care about API architecture for an MVP?
Shipping fast doesn't mean shipping messy. A single-file Express app with all routes and logic jammed into index.js works until you need to add authentication, a second resource, or error handling. Then you're refactoring under pressure. The Traversy Media Node/Express REST API Builder gives you a routes/controllers structure from day one that takes the same time to set up but saves hours when you need to iterate.
The key insight: your route files never change when you modify business logic. Your controllers never change when you adjust URL patterns. This independence is what lets you move fast later.
How do you go from zero to a working API in under an hour?
The workflow is 12 steps, but the first functional endpoint takes about 10 minutes:
1. Run `npm init -y`, add `"type": "module"`, install Express, body-parser, and nodemon.
2. Create index.js with Express app, bodyParser.json() middleware, and app.listen(5000).
3. Define your resource schema — what fields does one record have? Keep it minimal for the MVP.
4. Create /routes/resource.js with five router stubs.
5. Create /controllers/resource.js with a `let` array and five handler functions.
6. Mount the router in index.js.
7. Implement handlers: get-all, create (with uuid), get-one, delete, update (PATCH).
Use an in-memory array as your database. It resets on every server restart, but for testing your frontend integration, that's fine. You're not storing real user data yet — you're validating that your API contract works.
How do you extend this to multiple resources without a mess?
The pattern scales by multiplication. For each new resource (products, orders, comments), create one file in /routes and one file in /controllers. Mount each router in index.js under its own path prefix. Your index.js stays clean:
```javascript
app.use('/users', usersRoutes)
app.use('/products', productsRoutes)
app.use('/orders', ordersRoutes)
```
Each resource is fully self-contained. You can hand off the orders controller to a collaborator without them needing to understand the users controller.
When do you swap the mock array for a real database?
Swap when you need data persistence between server restarts — typically right before connecting your frontend or before any user testing. Because all data operations live in controller files, the swap is surgical: replace `users.push(newUser)` with a PostgreSQL INSERT query, replace `users.find()` with a SELECT query. Route files remain untouched.
Install the `pg` package, create a connection pool, and store your connection string in an environment variable. For PostgreSQL hosting, use Railway, Supabase, or Neon — all have free tiers sufficient for MVP traffic.
What pitfalls will slow down your launch?
The most common time-wasters for indie hackers using this pattern:
- Forgetting bodyParser.json() — you'll spend 30 minutes wondering why POST returns undefined. Register it before routes.
- Double paths — mounting at '/users' and writing '/users' in the router creates '/users/users'. Use '/' inside router files.
- Testing from the browser — browsers only send GET. Use Postman for POST, PATCH, DELETE.
- const vs let — your delete handler reassigns the array with filter(). Declare with `let`.
Avoid these and you'll have a working, testable API ready for frontend integration in a single session.
Your next step: define your MVP's primary resource, open a terminal, and start at step one.
// FREQUENTLY ASKED QUESTIONS
Is this Express API pattern good enough for production?
The route/controller architecture is production-grade and used by professional teams. For production, you need to add error handling middleware, input validation, authentication, and swap the in-memory array for a real database like PostgreSQL. The pattern itself doesn't need to change — you extend it by adding middleware layers and replacing the data store in controllers.
How fast can I build a CRUD API with this workflow?
A single-resource CRUD API with five endpoints takes 30-60 minutes following the 12-step workflow. Adding each additional resource takes 15-20 minutes since the pattern is identical — new route file, new controller file, new mount in index.js. The structure is repetitive by design, which is what makes it fast.
Should I use this or a BaaS like Firebase for my MVP?
Use Firebase or Supabase if you need zero backend code and are comfortable with vendor lock-in. Use this Express pattern if you need custom business logic, want full control over your API contract, or plan to migrate to your own infrastructure later. The Express approach takes more setup time but gives you complete flexibility.