
For years, create-react-app (CRA) was the undisputed king. It was the npx create-react-app my-app that launched a thousand projects. It gave us a modern, client-side-rendered (CSR) React setup with zero configuration. But the web evolved. The need for better SEO, faster initial page loads, and more integrated full-stack experiences grew. CRA, being purely client-side, started to show its age.
Enter Next.js, the full-stack React framework. And more recently, its new paradigm: the App Router.
Migrating from CRA to the Next.js App Router isn't just a "find and replace." It's a fundamental shift from a client-centric application to a server-centric one. This shift unlocks powerful features like Server-Side Rendering (SSR), Static Site Generation (SSG), and, most importantly, React Server Components (RSCs). The result is a faster, more powerful, and more SEO-friendly application.
Here’s a high-level guide to making the switch.
1. Setup and Folder Structure
You'll start by scaffolding a new Next.js project: npx create-next-app@latest. Choose "Yes" for using the app/ directory.
The folder structure is the first major change:
CRA:
src/pages/,src/components/,public/index.htmlNext.js (App Router):
app/,public/(noindex.html), and you can keep acomponents/folder.
Your App.js and index.css from CRA will conceptually merge into app/layout.jsx and app/globals.css. The app/layout.jsx is your new root, and it must define the <html> and <body> tags.
2. The New File-Based Routing
This is the biggest change. CRA used react-router-dom to define routes in a central file. The App Router uses a directory-based system.
CRA (react-router) | Next.js (App Router) |
|
|
|
|
|
|
|
|
To migrate, you will:
Identify your "pages" in CRA.
For each page, create a new folder in the
app/directory.Inside that folder, move your page component's content into a new file named
page.jsx.Replace all
react-router-dom's<Link>components with<Link>fromnext/link.
3. The Data Fetching Paradigm Shift
In CRA, you fetched data on the client inside a useEffect:
JavaScript
This is slow. The user gets a loading spinner while they wait for the JavaScript to load, then wait for the data to be fetched.
With the App Router, components are Server Components by default. This means they run on the server. You can fetch data directly inside them using async/await.
JavaScript
The user's browser receives the fully-rendered HTML with the data already included. There is no loading state. It's dramatically faster and perfect for SEO.
4. "use client": The Client-Side Opt-In
"Wait," you say, "what about useState or onClick? They don't work on the server!"
You are correct. This is the most important concept: Server Components cannot use hooks or interactivity.
When you need a component to be interactive (use state, effects, or event listeners), you must explicitly mark it as a Client Component by placing the "use client" directive at the very top of the file.
JavaScript
Your app/blog/page.jsx (Server Component) can then import and render this Counter (Client Component). This is the "hybrid" model: fetch data on the server, and send interactive "islands" of JavaScript to the client.
The migration is an investment. You're not just moving files; you're re-architecting your application to be faster, more efficient, and more powerful.