Insight
Learning Next.js by Building
I've been a frontend developer for many years, but React and Next.js are relatively recent additions to my stack. Rather than working through tutorials, I decided to learn by building my own portfolio site from scratch — deliberately, with attention to why things work the way they do.
I've been building for the web since 2006. I've worked through server-rendered PHP, early Angular, jQuery spaghetti, CMS platforms, and plenty of custom solutions in between. But React and Next.js came into my stack later than they might have for someone who started more recently. And when I decided to properly learn them, I made a deliberate choice: no tutorial projects, no to-do apps. I'd build something real.
That something real is this website. And it has taught me more in a few months than I think I'd have learned in a year of following along with courses.
The first thing that genuinely surprised me was how different the App Router is from everything I'd read about it. I understood the concept — file-based routing, layouts, nested pages — but the mental model took a while to settle. The fact that everything in the app directory is a Server Component by default isn't just a detail. It changes how you think about every component you write. My instinct kept reaching for useState and useEffect, and I kept having to ask myself: does this actually need to run in the browser?
That question — server or client? — turns out to be one of the most useful frames in modern React. Once I stopped treating 'use client' as the default and started treating it as a deliberate decision, the architecture of the App Router started making a lot more sense.
The other big lesson was generateStaticParams. I understood static generation in theory, but writing it out for the first time — telling Next.js exactly which dynamic routes should exist at build time — made it concrete in a way theory doesn't. The same goes for generateMetadata, for notFound(), for error.tsx and loading.tsx. These aren't just API details. They're a system for handling the full lifecycle of a page, and building with them is how you understand why they work the way they do.
The thing I keep coming back to, though, is the abstraction question. I built PreviewCard before I had three different card types. I didn't build a Grid component, even though I needed grids. I didn't create helper libraries early. Every time I was tempted to abstract something preemptively, I waited — and usually I was glad I did. The right abstraction becomes obvious when you've repeated yourself enough to actually see the pattern. The wrong abstraction, built too early, just creates indirection you have to work around later.
If you're coming to Next.js with experience from other frameworks, my advice is this: give yourself permission to feel confused for a bit. The concepts aren't hard, but the mental model shift — especially around Server Components and the rendering pipeline — takes time to internalise. Build something you care about. Make real decisions. The understanding comes from the doing.