next-12-to-13
Upgrade your Next.js 12 project to Next.js 13
Example
# This plan was created using the guide from https://nextjs.org/docs/app/building-your-application/upgrading/app-router-migration
constants:
cleanup_files:
- pages/_app.js
- pages/_document.js
setup:
- name: get_content_from_file
arguments:
path_to_file: .gitignore
returns: gitignore_contents
- name: if_else
condition: '{{ gitignore_contents }}'
else:
tools:
- name: create_file
arguments:
path_to_file: .gitignore
file_contents: |
node_modules
.pnp
.pnp.js
# Testing
coverage
# Production
build
dist
# Environment variables
.env
.env.*
!.env.example
# Logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
# Editor directories and files
.DS_Store
.vscode
.idea
*.swp
*.swo
- name: run_terminal_command
arguments:
command: npm install next@latest react@latest react-dom@latest
- name: run_terminal_command
arguments:
command: npm install -D eslint-config-next@latest
steps:
# Step 1: Ensure Node.js version is >= v18.17
- name: Check Node.js version
tools:
- name: run_terminal_command
arguments:
command: node -v
returns: node_version
# - name: assert
# arguments:
# condition: "{{ node_version | version_compare('>= 18.17') }}"
# message: "Node.js version must be >= v18.17"
# Step 2: Create the app directory
- name: Create the app directory
tools:
- name: create_directory
arguments:
path_to_directory: app
# Step 3: Create a Root Layout
- name: Create Root Layout
tools:
- name: create_file
arguments:
path_to_file: app/layout.tsx
file_contents: |
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Home',
description: 'Welcome to Next.js',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
# Step 4: Migrate next/head to Metadata API
- name: Migrate next/head to Metadata API
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.tsx$'
returns: tsx_files
- name: async_each
items: '{{ tsx_files }}'
each_item:
item_name: tsx_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ tsx_file }}'
edit_prompt: |
If this is a file with next/head usage, replace it with Metadata API as shown below:
Before:
import Head from 'next/head'
export default function Page() {
return (
<>
<Head>
<title>My page title</title>
</Head>
</>
)
}
After:
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'My Page Title',
}
export default function Page() {
return '...'
}
# Step 5: Migrate pages to app directory
- name: Migrate pages to app directory
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.tsx$'
path_to_directory: pages
returns: page_files
- name: async_each
items: '{{ page_files }}'
each_item:
item_name: page_file
tools:
- name: create_file
arguments:
path_to_file: "app/{{ page_file | replace('pages/', '') }}"
file_contents: |
import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Page',
description: 'Migrated page',
}
export default function Page() {
return '...'
}
# Step 6: Migrate routing hooks
- name: Migrate routing hooks
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.(tsx|ts|jsx|js)$'
returns: react_files
- name: async_each
items: '{{ react_files }}'
each_item:
item_name: react_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ react_file }}'
edit_prompt: |
If this file uses the useRouter hook from 'next/router', replace it with the new routing hooks from 'next/navigation':
Before:
import { useRouter } from 'next/router'
After:
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
# Step 7: Migrate data fetching methods
- name: Migrate data fetching methods
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.(tsx|ts|jsx|js)$'
returns: react_files
- name: async_each
items: '{{ react_files }}'
each_item:
item_name: react_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ react_file }}'
edit_prompt: |
If this file uses getServerSideProps or getStaticProps, replace them with the new data fetching methods:
Before:
export async function getServerSideProps() {
const res = await fetch(`https://...`)
const projects = await res.json()
return { props: { projects } }
}
After:
async function getProjects() {
const res = await fetch(`https://...`, { cache: 'no-store' })
const projects = await res.json()
return projects
}
export default async function Page() {
const projects = await getProjects()
return (
<ul>
{projects.map((project) => (
<li key={project.id}>{project.name}</li>
))}
</ul>
)
}
# Step 8: Migrate environment variables
- name: Update environment variables
tools:
- name: find_files_by_name_with_regex
arguments:
find_file_name_pattern: '.env$'
returns: env_files
- name: async_each
items: '{{ env_files }}'
each_item:
item_name: env_file
tools:
- name: edit_file
arguments:
path_to_file: '{{ env_file }}'
edit_prompt: |
Change all environment variables with the REACT_APP_ prefix to NEXT_PUBLIC_
# Step 9: Update scripts in package.json
- name: Update scripts in package.json
tools:
- name: edit_file
arguments:
path_to_file: package.json
edit_prompt: |
this is a package.json file for a Next.js 12 application. Please add the following scripts:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
}
}
# Step 10: Clean Up
- name: Clean Up
tools:
- name: async_each
items: '{{ cleanup_files }}'
each_item:
item_name: cleanup_file
tools:
- name: delete_file_or_folder
arguments:
path_to_target: '{{ cleanup_file }}'
- name: run_terminal_command
arguments:
command: npm uninstall react-scripts
Last updated