Stop 17 · System Design for Full-Stack AppsTopics · 5/7

Designing a Full-Stack Feature

Part of the Full Stack Developer Roadmap

In short

"Add bookmarks" sounds like one task. It's really a screen, an API contract, a table and some edge cases. Designing them together before coding saves days of rework.

Practicing the complete design process for a real feature — from UI mockup through API contract, database schema, and back — the exact skill a full-stack role actually exercises daily.

The purple blob in a chef's hat sketches a new dish on a notepad beside an empty plate.

Think of it like this

Adding a new dish to the menu

A chef doesn't start by frying. First they picture the plate, then write the recipe, then check the store room has the ingredients and the right size pans. Screen first, then the contract, then the data, then the cooking.

Watch it happen

Designing "Bookmark a post"

UI sketch
API contract
Schema
Backend
Frontend
Ship

1/6Sketch the bookmark icon on each post and a 'Saved' page. Note the states: empty, loading, error, saved.

The big ideas

What you need to know

Start from the screen

What the user sees decides what the API returns and what the database must answer quickly.

The contract comes first

Agree on URLs and JSON shapes before coding, so frontend and backend can be built side by side.

List the unhappy paths

Double clicks, slow networks, deleted data and logged-out users. Design for them on paper first.

Ship in small slices

A thin end-to-end slice that works beats three perfect layers that don't connect yet.

See it in code

Walk through the code

ts
1// shared/bookmarks.ts: imported by both the Next.js app and the API2import { z } from "zod";3 4export const BookmarkInput = z.object({ postId: z.string().uuid() });5export type BookmarkInput = z.infer<typeof BookmarkInput>;6 7export const BookmarkList = z.object({8  items: z.array(z.object({ postId: z.string(), title: z.string(), savedAt: z.string() })),9  nextCursor: z.string().nullable(),10});11export type BookmarkList = z.infer<typeof BookmarkList>;12 13// POST   /api/bookmarks          body BookmarkInput   201, or 409 if already saved14// DELETE /api/bookmarks/:postId                       20415// GET    /api/bookmarks?cursor=                       200 BookmarkList

1/3One zod schema gives you runtime validation on the server and a TypeScript type for the client.

The contract as code. The API validates requests with these schemas, and the frontend uses the same types, so a renamed field breaks the build instead of production.

Save yourself the pain

Common mistakes

Oops

Building the database first and then forcing the screen to fit whatever the tables return.

Do this instead

Sketch the screen, list exactly what it shows, then design the API and tables to serve that.

Oops

Only designing the happy path where everything works first time.

Do this instead

Write down empty, loading, error and duplicate cases before coding, and decide what each one shows.

Your mission

Design one feature on paper

~30 min

Quick check

Two teammates will build the frontend and backend of a feature in parallel. What should they agree on first?

Go deeper

  1. 1Pick a feature, e.g. a commenting system, and design the schema, API endpoints, and UI states together.
  2. 2Identify what can be built in parallel once the API contract is agreed on.
  3. 3Consider edge cases at each layer: empty states, errors, concurrent edits.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge