Next.jsReactweb development

Next.js for React developers: what actually changes

A hands-on look at file-based routing, server and client components, and the one mental shift that makes Next.js click.

WebPrims Team12 September 20263 min read
Next.js for React developers: what actually changes

Every June we get a student who knows React well. They've built a few components, they understand state, they can explain props. Then they open a Next.js project and feel lost. The JSX is the same. The components look the same. But the file structure is unfamiliar, and there's a "use client" line at the top of some files that nobody explained. This post is for that person.

What Next.js actually is

Next.js is a framework built on React. It does not replace React. You still write components, you still use hooks, you still think in props and state. What Next.js adds is the infrastructure around your components: routing, rendering decisions, caching, and a deployment story.

For a React developer, the learning curve is not about the language. It's about conventions. Three things trip people up: file-based routing, server components, and the render-time decision. We'll take each one.

The file system is the router

In plain React, you install react-router-dom and configure routes in code. In Next.js, the file system is the router. A file at app/about/page.tsx becomes the page at /about. A file at app/blog/[slug]/page.tsx becomes /blog/anything-here, where [slug] is a dynamic segment you read from the URL.

Here's a minimal example. Create a project with npx create-next-app@latest my-blog, then make a file at app/posts/[id]/page.tsx:

export default async function PostPage({ params }: { params: { id: string } }) {
  const post = await getPost(params.id);
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.body}</p>
    </article>
  );
}

That's it. No route registration, no <Routes> wrapper. The URL structure mirrors the folder structure. When a request comes in for /posts/42, Next.js matches the [id] folder, sets params.id to "42", and renders this component.

This convention is easy to learn but easy to forget when you're used to explicit route tables. Every time we see a student reach for a router package inside Next.js, we stop them. You don't need it.

Server components and client components

The biggest mental shift is the execution context. In Next.js, every component is a server component by default. It runs on the server, not in the browser. That means you cannot use onClick, useState, window, document, or any browser API in a server component. The code still compiles and renders, but the interactive parts just won't work — or worse, they'll throw errors at runtime.

To opt into browser behavior, add "use client" at the very top of the file. That directive tells Next.js: this component and everything it imports runs in the browser.

Here's the classic counter that confuses everyone:

"use client";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Without the "use client" line, this file fails to compile because useState is a hook that needs a browser environment. With the line, it works exactly like a React component.

Why does Next.js default to the server? Because server components can fetch data, read databases, and render HTML before the browser receives anything. That's the whole point: fast first load, good SEO, less client-side JavaScript. You only push interactivity to the browser where you actually need it.

The common mistake is putting "use client" at the top of every file out of habit. We see this in week two of every cohort. Resist the urge. Ask yourself: does this component need browser APIs? If not, leave it on the server.

The render-time decision

Plain React renders in one way: the browser downloads JavaScript, runs it, and the page appears. Next.js gives you a choice, and the choice happens per page. A page can be static, generated once at build time — great for blog posts and documentation. It can be dynamic, generated per request — the right call for dashboards and user-specific data. Or it can be client-side, rendered in the browser after a JavaScript download, which is what plain React does.

In the app directory, you control this with code. If your page component is async and fetches data at request time, it's dynamic. If you export a generateStaticParams function, Next.js pre-renders those pages at build time. If you add "use client" and fetch in the browser, it's client-side.

The first time this clicks for a student is usually when they realize they can query a database directly inside an async server component. No API endpoint, no

Come and sit a class before you decide

Reading about it only gets you so far. Pick a day, sit in on a class that is already running, write some code, and talk to the students in it. Free, and nothing to pay afterwards unless you want to join.

Next.jsReactweb development

Found this useful?

Share it with someone who is learning.

CallWhatsAppFree demo