Skip to main content
ngockhoi96

Top-down, bottom-up, and the way I actually build

I scrolled past a claim that innovation only happens bottom-up, got curious, and fell down a rabbit hole: what top-down and bottom-up actually mean, and how I oscillate between them.

ngockhoi96 Thoughts 9 min read
A loop between a top-down sketch and a bottom-up build, each feeding the other.

I wasn’t looking for a mental model. I was scrolling a post about learning roadmaps when two words kept circling each other, top-down and bottom-up, and then, a few days later, a separate line from Lê Hoàng Dũng snagged on the same hook: Innovation happens from the bottom up, not the top down. I didn’t have a strong opinion. I had a question. This post is me chasing it down rather than answering it.

Two directions, one problem

Strip away the field and both words describe the direction you move through a problem.

Top-down starts with the whole and works down to the parts: you sketch the big picture first (the goal, the system, the outline), then decompose it until each piece is small enough to build. Bottom-up does the reverse: you build the smallest concrete pieces first, get them solid, then compose them upward until a whole emerges.

That’s the entire distinction. Everything else is this same split wearing different clothes. I wrote both up as short reference entries, Top-down and Bottom-up in the Lexicon, so this post can stay about the thinking rather than the definitions.

Where they came from

Neither word is new, and the software lineage is surprisingly specific. The top-down idea was crystallised by Niklaus Wirth in his 1971 paper Program Development by Stepwise Refinement Refine a vague specification in small steps until it becomes a working program (refine a fuzzy specification step by step until it becomes a program) and pushed into industry practice by Harlan Mills and others at IBM under the banner of structured programming. Bottom-up grew up alongside it as the natural complement: the way you actually build when you trust your primitives more than your plan.

The same split, in three rooms

The reason these words travel so far is that the problem is always the same shape. You just meet it in different rooms.

Software

Top-down: design the architecture and module boundaries first, then fill in each function. Bottom-up: build small, well-tested pieces and compose them upward, the spirit of Atomic Design.

In practice the line blurs, and my messiest case is a work project. We were handed a deliberately vague mandate, build a platform where people drag blocks around and ship a whole website, and not much else. No real requirements, so nobody designed the architecture up front. We shipped proof-of-concept after proof-of-concept for the bosses to react to, redid them, and grew an MVP out of the churn. The supposedly top-down artifacts, the PRD, the wireframes, the system-design docs, the ADRs, the “final” techstack, only crystallised after the MVP showed us what we were building; before that they changed every few weeks. What was genuinely top-down was barely more than the goal. What was bottom-up was everything that gave the thing its shape: a NestJS and MySQL backend that grew into a Hexagonal, DDD layout, a React front end that found its seams as Feature-Sliced Design, a Turborepo that ended at four apps and a dozen-plus packages, the AWS plumbing, EKS, Lambda, S3, CloudFront, added as each real problem arrived. The architecture diagram was a picture of where we landed, not a map we’d followed. This blog is the cleaner, solo version of the same story, a section down.

Software: top-down decomposes architecture and its cloud infra into functions; bottom-up composes utilities into pages.
Software: decompose down, or compose up.

Planning and teams

Top-down: leadership sets a goal (“grow revenue 20% this quarter”) and cascades it into tasks. Bottom-up: the people closest to the work surface proposals, and strategy is assembled from what they find. On my teams it usually runs upward. We brainstorm, stand up a quick proof of concept and a proposal, sharpen it together, break it into small issues, then build them one by one until the shape is real. The planning world even has a name for doing both at once, counter-flow planning: leadership sets the guidelines, the people doing the work push back with what’s feasible, and the plan is the negotiation between them. Same split, another room.

Teams: top-down cascades a goal down into tasks; bottom-up surfaces proposals up into strategy.
Planning and teams: cascade down, or surface up.

Learning

Top-down: jump into building the thing you want, and back-fill theory when you hit a wall. Bottom-up: master the fundamentals (data structures, syntax, the cascade) and only then build something with them.

Learning: top-down builds first and back-fills theory; bottom-up masters the fundamentals first.
Learning: build-first, or fundamentals-first.

This is the room I’ve lived in longest, so it gets the long version. I learned to code through F8, which runs HTML → CSS → JS → React, a curriculum that looks bottom-up. And on paper it was: fundamentals first, then build. Honestly, that’s how it felt, too. I started from zero, did the exercises, built tiny UIs, and kept smacking into silly bugs. What surprised me later is that most of them weren’t knowledge gaps. They were experience gaps. I knew the syntax; I just hadn’t built enough to have instinct yet. Bottom-up handed me real bricks, but it never showed me what I was building toward. The whole picture (that a web app is backend, frontend, devops, security, testing, and infrastructure all at once) only arrived top-down, once I was at work shipping small features and fixing trivial bugs inside a system someone else had already shaped. My honest take: bottom-up fundamentals are necessary but not sufficient. Stay down there too long, polishing toy libraries and tiny apps without leveling up into real, messy, top-down work, and you spend a lot of time becoming a coder the slow way. I think so, anyway.

Right after F8 I felt the pull of bottom-up for the first time. A revision exercise, a tiny quiz app, was meant to be throwaway. But each small function I wired up actually worked, and “it works” is addictive. So I kept going: a leaderboard, usernames, settings, timers, then fussing over typography and color long after the logic was done. Nudged along by a Web Dev Simplified build from Kyle, I grew it into quiz_app_vanillajs. And then it just stopped: no real database, no realtime, no auth.

If that sounds like GoHome a few sections down, it should: the same bottom-up habit, years apart. Build the smallest thing, fall for the building itself, and never hit a top-down line that says done.

The contrast came recently. I wanted a Word Search game to play with friends, and for once I didn’t open an editor first. I researched, grilled an AI to think it through, and pinned down a real design doc before any code: functional and non-functional requirements, domain models, the grid and scoring algorithms, a system-architecture sketch, a phased breakdown, and the tech-stack decisions. Only then did I build, bottom-up, against that roadmap. F8 taught me bottom-up by default; Word Search was me choosing top-down on purpose, and finally feeling the difference.

How I actually built this blog

Here’s the cleanest case study I have, because you’re reading it.

This site has a strong top-down spine: a CONTEXT.md glossary that fixes the language before the code, and a stack of ADRs that decide the why before the how. That’s about as top-down as it gets. The shape is argued out on paper first.

And yet almost none of it was built that way. The components grew bottom-up: a button recipe, then a tag, then a card, then, only once enough pieces existed, a layout that composed them. The top-down documents were often written after the bottom-up discovery, to lock in a pattern I’d already stumbled into.

How this blog grew: a single Astro app with flat folders becomes a Bun-workspace monorepo (apps/site + packages/db) with domain-grouped components, theme/ and plugins/, Cloudflare D1/KV/R2, and Pagefind, built bottom-up with the docs written after.
How the blog actually grew: bottom-up, with the docs written after.

The clearest case was Phase 0 of this very site. Instead of polishing components, I deliberately stayed at altitude: scaffolding, placeholders, throwaway dummy posts, just enough of a list page and a detail page to push real markdown through the whole pipeline: process, render, build, deploy. Proving the whole loop end to end before perfecting any single part is pure top-down, and it saved me from the classic bottom-up trap: a drawer full of beautiful components and no working site. Even the calls before that, comparing stacks and picking the infrastructure to reach a deployable MVP fast, were top-down bets, not bottom-up tinkering.

┌───────────── prove the whole loop, end to end ──────────────┐
│ │
▼ │
markdown ─▶ process ─▶ render ─▶ build ─▶ deploy ──────────────┘
dummy remark/ HTML + astro Cloudflare
posts rehype CSS Workers
└─▶ then go back and deepen each part, bottom-up

And the reverse keeps happening too. A lot of this site’s rules and tools are fossils of building, not foresight. The PandaCSS shorthand convention (always px, mx, bg, never the longhand) I didn’t decree up front; I kept hand-fixing the same slips until the pattern was undeniable, then froze it into a PostToolUse hook that flags it on every edit. The colon foot-gun was the same: nobody predicts that 9:00 in prose gets eaten by the directive parser until they hit it. To the parser, that colon looks like the start of a directive:

9:00 parsed as → "9" + :00 ← a directive named "00", renders broken
9:00 rescued as → "9" + ":00" ← reverted to plain text, renders 9:00 ✓

So I debugged it and wrote a small remark plugin that reverts any unclaimed :thing back to literal text, and now prose colons just work.

The site’s look came up from the floor the same way. I built the 3D “pressable” feel by hand because I wanted to dodge the sea of identical UI kits out there, just one button I liked at first. Then I went looking for why it worked: Dominik’s year-in-review and Sentry’s redesign writeup sharpened the design thinking, and I folded what I learned into a version that’s mine. Only once I’d built enough surfaces did it settle into a reusable token tier.

And underneath all of it, the quiet payoff: hand-building every component taught me more about HTML, CSS, the Web APIs, accessibility, and UI/UX than any tutorial did. None of that was on a design doc. The building wrote it.

Pros and cons

Neither is better. They fail in opposite directions, which is exactly why you want both.

Top-downBottom-up
Starts fromThe goal, the whole systemThe parts, the foundations
StrengthKeeps direction; you rarely lose the goalFeasibility and quality; every brick is sound, results come early
WeaknessThe hard details hide at the bottom; the plan can stay vagueEasy to lose the overview; good parts that don’t add up
Fails whenThe big picture is wrong, and everything below inherits the mistakeThe pieces never converge on the actual goal
Best whenThe goal is clear; the path isn’tThe goal is fuzzy; the materials are solid

The rabbit hole: which one innovates?

This is the question that pulled me in, so it’s only fair to end where I started, though I’ll be upfront that it’s the part I’m least sure about.

Innovation happens from the bottom up, not the top down.

— Lê Hoàng Dũng

The more I read, the more I think the quote is half of a truer sentence. Bottom-up is where ideas are born: Gmail came out of Google’s 20% time, the Like button out of a Facebook hackathon, neither from an executive directive. But top-down is where ideas get resources and reach: the iPhone and SpaceX’s Mars goal were top-down bets that no individual engineer could have funded or authorised. The version that rings true to me: innovation sparks bottom-up, but scales top-down. Kill either half and most ideas die, as forgotten demos or as expensive visions disconnected from reality.

I mostly agree, and GoHome is my own evidence, just not the way I expected. It’s the grown-up version of the quiz-app habit from way back: the same itch, more years of practice on it. GoHome began as the smallest bottom-up itch: learn Go, and stop forgetting what I did all day by generating my daily report straight from git history, ready to paste before I went home. The goal was tiny, so I built it the tiny way: from scratch, no upfront architecture, no roadmap, just one working piece after another. And it worked: more commands, config formats, tests to 100% on the core, eleven releases deep. But that’s also why it has no ending. With no top-down spine, nothing ever told me it was done. The roadmap just keeps growing (AI-written summaries next, and more), and I paused only when life pulled me off it, still using the basic feature daily. That’s bottom-up in one repo: it hands you something real and solid, fast, and never quite knows when to stop. The spark was bottom-up; the one thing it always lacked was a top-down line that said enough.

The hybrid, and my rule

So I never really resolved the original question, and I’ve made peace with that. The useful output wasn’t an answer. It was a rule of thumb.

Use top-down to stay oriented; use bottom-up to stay honest. Sketch the whole so you know which direction is forward, then build the parts so reality gets a vote. When they disagree, and they will, believe the parts and rewrite the sketch. The skill isn’t picking a side. It’s noticing which one you’ve been leaning on too long, and deliberately switching.

A roadmap, it turns out, is both words at once: top-down gives you the map, bottom-up builds the road, and you reach nowhere without doing both.

Written by ngockhoi96

A developer writing about web engineering, Astro, Cloudflare, and the craft of building lasting software.