Migration strategy for existing apps with Cache Components
With Cache Components enabled, instant navigation validation flags every route that reads the session. You don't have to resolve them all before shipping. Set 'export const instant = false' on the page or layout to let it keep blocking on the server, then adopt the patterns one route at a time.
Cache Components equivalent to Pages Router patterns
In migration from Pages Router: fallback: true in getStaticPaths is now the default with cacheComponents (visitors get a Suspense fallback instantly with streaming content); router.isFallback is not needed as the prerendering step generates a static shell; getStaticProps with revalidate maps to 'use cache' with cacheLife; getStaticPaths maps to generateStaticParams.
Update package.json scripts for Next.js
Update `package.json` scripts to use Next.js commands: `"dev": "next dev"`, `"build": "next build"`, and `"start": "npx serve@latest ./build"`. Add `.next` and `next-env.d.ts` to `.gitignore`.
Create React App migration overview
To migrate from Create React App (CRA) to Next.js, start by treating your application as a purely client-side application (SPA) without immediately replacing your existing router. This reduces complexity and merge conflicts. You can then adopt Next.js features incrementally.
CRA to Next.js: Step 1 - Install dependency
Install Next.js using one of these commands: `pnpm add next@latest`, `npm install next@latest`, `yarn add next@latest`, or `bun add next@latest`.
CRA to Next.js: Step 2 - Create next.config.ts
Create a `next.config.ts` file at the root of your project (same level as `package.json`). For SPA migration, use `output: 'export'` to output a static Single-Page Application and optionally set `distDir: 'build'` to change the build output directory. Note: Using `output: 'export'` means you will not have access to server-side features like SSR or APIs. You can remove this line later to leverage Next.js server features.
CRA to Next.js: Step 3 - Create root layout
Create an `app` directory at your project root or inside `src`, then create `app/layout.tsx` (or `.js`). This React Server Component wraps all your pages. Copy the content from your old `public/index.html` into the RootLayout component, replacing `body div#root` (and `body noscript`) with `<div id="root">{children}</div>`.
Next.js auto-includes metadata meta tags
Next.js automatically includes `<meta charset="UTF-8" />` and `<meta name="viewport" content="width=device-width, initial-scale=1" />` tags, so you can remove them from the `<head>` in your layout.
Metadata files auto-added to head
Metadata files such as `favicon.ico`, `icon.png`, and `robots.txt` are automatically added to the application `<head>` tag as long as they are placed in the top level of the `app` directory. You can safely delete their `<link>` tags from your layout.
Use Metadata API for head content
Use the exported `metadata` object in your layout to manage page metadata like title and description. Export a `metadata` object of type `Metadata` with properties like `title` and `description` instead of declaring these in `<head>` tags.
CRA to Next.js: Step 5 - Styles
Next.js supports CSS Modules out of the box and also supports global CSS imports. For global CSS, import your CSS file at the top of `app/layout.tsx`. For Tailwind CSS, see the Next.js installation docs.
CRA to Next.js: Step 6 - Create entrypoint with catch-all route
To keep the app as an SPA during migration and intercept all routes, create a `[[...slug]]` directory inside `app` with a `page.tsx` file. Use `generateStaticParams()` returning `[{ slug: [''] }]` to generate a single route for the empty slug (`/`), mapping all routes to the same page. This page is a Server Component prerendered into static HTML.
CRA to Next.js: Step 7 - Embed CRA app in Client Component
Create a `client.tsx` file in `app/[[...slug]]/` with the `'use client'` directive. Use `dynamic` import from `next/dynamic` with `ssr: false` to import your CRA root App component. This makes the App component truly client-only (SPA). Then update your `page.tsx` to render this client component.
Static image imports in Next.js return objects
In CRA, importing an image returns a string URL. In Next.js, static image imports return an object. Use the object's `src` property with `<img>` tags: `<img src={logo.src} />`, or use the whole object with the Next.js `<Image>` component.
Convert absolute image imports to relative
Change imports of images from `/public` from absolute to relative paths. For example, change `import logo from '/logo.png'` to `import logo from '../public/logo.png'`.
Environment variables: REACT_APP_ to NEXT_PUBLIC_
Next.js requires a `NEXT_PUBLIC_` prefix for any environment variable you want to expose in the browser. Change all environment variables with the `REACT_APP_` prefix to `NEXT_PUBLIC_`.
Dev server runs on http://localhost:3000
After setting up scripts, run `pnpm dev`, `npm run dev`, `yarn dev`, or `bun dev` to start the development server. Open http://localhost:3000 to view your application.
Clean up CRA-specific files
After migration, you can remove these CRA artifacts: `public/index.html`, `src/index.tsx`, `src/react-app-env.d.ts`, the `reportWebVitals` setup, and the `react-scripts` dependency from `package.json`.
Replicate CRA homepage with basePath
If you used the `homepage` field in your CRA `package.json` to serve the app under a specific subpath, replicate it in Next.js by setting the `basePath` configuration in `next.config.ts`. For example, `basePath: '/my-subpath'`.
Migrate custom Service Worker
To register a custom service worker in Next.js, use: `await navigator.serviceWorker.register(new URL('../serviceWorker.js', import.meta.url), ...)`. Refer to Next.js Progressive Web Applications (PWAs) documentation for more details.
Replicate CRA API proxy with Next.js rewrites
If your CRA app used the `proxy` field in `package.json` to forward requests to a backend server, replicate this with Next.js rewrites in `next.config.ts` using the `rewrites()` function. Define source and destination patterns to forward requests.
Migrate custom Webpack or Babel configuration
If you had custom webpack or Babel configuration in CRA, you can extend Next.js's config in `next.config.ts` using the `webpack` property. Modify the webpack config by returning the modified config object.
Custom webpack requires --webpack flag
When using custom webpack configuration in `next.config.ts`, you must add `--webpack` to your `dev` script to enable it: `next dev --webpack`.
TypeScript setup for Next.js
Next.js automatically sets up TypeScript if you have a `tsconfig.json`. Make sure `next-env.d.ts` is listed in your `tsconfig.json` `include` array along with your app and src directories.
Add next-env.d.ts to TypeScript include for image imports
If you encounter TypeScript errors when accessing the `src` property of imported images, add `next-env.d.ts` to the `include` array of your `tsconfig.json`. Next.js will automatically generate this file when you run your application.
Static export does not support useParams hook
Using `output: 'export'` in `next.config.ts` does not currently support the `useParams` hook or other server features. To use all Next.js features, remove `output: 'export'` from your configuration.
Why migrate from CRA: slow initial page loading
Create React App uses purely client-side rendering, causing slow initial page loading. The browser must wait for the React code and entire application bundle to download and run before requesting data, and application code grows with every new feature and dependency.
Why migrate from CRA: no automatic code splitting
CRA does not provide automatic code splitting. Manual code splitting can inadvertently introduce network waterfalls. Next.js provides automatic code splitting and tree-shaking built into its router and build pipeline.
Why migrate from CRA: network waterfalls
A common performance issue occurs when applications make sequential client-server requests to fetch data. In SPAs, a child component can only begin fetching data after its parent finishes, resulting in a waterfall of requests. Next.js lets you move data fetching to the server, often eliminating these waterfalls.
Why migrate from CRA: streaming with Suspense
Next.js has built-in support for streaming through React Suspense. You can define which parts of your UI load first and in what order without creating network waterfalls, enabling you to build faster-loading pages and eliminate layout shifts.
Why migrate from CRA: choose data fetching strategy
Next.js allows you to choose your data fetching strategy on a page or component-level basis. For example, you could fetch data from your CMS and render blog posts at build time (SSG) for quick load speeds, or fetch data at request time (SSR) when necessary.
Why migrate from CRA: built-in optimizations
Next.js includes specialized components and APIs that automatically optimize images, fonts, and third-party scripts, which often have a large impact on application performance.
Next.js Proxy feature
Next.js Proxy allows you to run code on the server before a request is completed. For instance, you can avoid a flash of unauthenticated content by redirecting a user to a login page in the proxy for authenticated-only pages. You can also use it for features like A/B testing, experimentation, and internationalization.