In short
Your database schema outlives your UI. Pages get redesigned every year, but tables stay for a long time. A bit of planning now saves you from painful migrations and weird bugs later.
Planning your tables/collections, fields, and relationships before writing code — the decisions here shape how easy (or painful) your API will be to build later.

Think of it like this
Stocking a new medical store
Before opening, the chemist decides which shelf holds what: tablets by company, syrups together, a separate register for prescriptions. Do it right and any medicine is found in seconds. Dump everything in one cupboard and every order turns into a search party.
Watch it happen
A small shop's tables
1/4Start with the nouns of your app. Each one becomes a table.
The big ideas
What you need to know
Store each fact once
Keep the user's email only in users. If it's copied into orders too, the two will drift apart.
Many-to-many needs a join table
Students and courses, orders and products: add a middle table with both ids, plus anything about the link itself.
Freeze history
Save the price on order_items at checkout. If the product price changes later, old orders must not change.
Design from your API
List the screens and endpoints first. Each GET should be answerable with a simple query or one join.
See it in code
Walk through the code
1CREATE TABLE users (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, email TEXT UNIQUE NOT NULL);2CREATE TABLE products (3 id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,4 name TEXT NOT NULL,5 price_paise INT NOT NULL CHECK (price_paise >= 0)6);7CREATE TABLE orders (8 id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,9 user_id BIGINT NOT NULL REFERENCES users(id),10 status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'paid', 'shipped')));11CREATE TABLE order_items (12 order_id BIGINT REFERENCES orders(id) ON DELETE CASCADE,13 product_id BIGINT REFERENCES products(id),14 qty INT NOT NULL CHECK (qty > 0),15 price_paise INT NOT NULL, -- price at the time of the order16 PRIMARY KEY (order_id, product_id));1/4Two independent tables: users and products. Each has its own id.
Money is stored in paise as whole numbers, so there are no rounding surprises.
Save yourself the pain
Common mistakes
Oops
Storing a comma-separated list like tags = 'react,node,sql' in one column.
Do this instead
Use a separate table (or a Postgres array if you never query inside it). Lists in strings can't be indexed or joined well.
Oops
Referencing the product's current price when showing an old order.
Do this instead
Copy the price into order_items when the order is placed. History should not change when prices do.
Your mission
Design a college events app
Quick check
A student can join many clubs and a club has many students. How do you model it?
Go deeper
- 1Design a schema for a real feature, e.g. a blog with posts and comments, before coding it.
- 2Practice identifying one-to-many and many-to-many relationships and how to model each.
- 3Consider what your frontend will actually need to query when designing the schema.
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.