Appearance
What APIs hide
ORMs, N+1, and "why is this endpoint slow" - the stuff that leaks through into your Network tab.
The polite translator
Your FE rarely speaks SQL. It speaks HTTP + JSON. Behind the controller there's often:
- an ORM (Prisma, Eloquent, Django ORM, SQLAlchemy, …)
- or a query builder
- or hand-written SQL (rare in startups, common in hot paths)
Same destination. Different accents.
ts
// Prisma-ish vibe
const contacts = await prisma.contact.findMany({
where: { deletedAt: null, companyId: 1 },
include: { company: true },
take: 20,
})Roughly becomes a SELECT + JOIN (or two queries). Knowing SQL means you can guess which.
N+1 - the classic FE-visible bug
Bad pattern on the server:
text
SELECT * FROM contacts WHERE company_id = 1; -- 1 query
for each contact:
SELECT * FROM companies WHERE id = ?; -- N queriesYour contact list of 50 people → 51 round-trips. The endpoint feels mysteriously slow. The waterfall in APM tools looks like a picket fence.
Fixes you've heard in standup:
JOIN/include/ eager load in one (or two) queries- dataloader-style batching
- denormalize a display field if you must (careful)
When a list page crawls after "we added the company name to each row", ask about N+1. You'll sound dangerous in a good way.
Over-fetching and under-fetching
| Problem | FE symptom | SQL angle |
|---|---|---|
| Over-fetch | huge JSON, unused fields | SELECT * / fat includes |
| Under-fetch | many tiny requests | missing JOIN / include; chatty API |
GraphQL and careful REST both try to land in the middle. SQL skills help you describe what you actually need.
When to peek at SQL
I don't think every FE should live in psql. I do think you should peek when:
- a screen is slow and the payload isn't huge
- a filter/sort/pagination bug smells like OFF-by-one in
LIMIT/OFFSET - you're designing a feature and need to sketch tables with a backend person
- an ORM error mentions a constraint you want to understand
Migrations are schema PRs
When someone adds deleted_at or a new deals.stage value, that's a migration - a versioned ALTER / CREATE. Reading those PRs is easier once you've written CREATE TABLE yourself.
Where to go next
- Practice: break the CRM schema, add
tags, addclosed_at - Read one real migration in a work project end-to-end
- Try the same queries on Postgres if you have it - notice what stays the same
- Cheatsheet lives next door for the rainy day
You've got enough SQL to stop treating the database as pure mysticism. The rest is reps.
Enjoy!
Best,
-- ł.