업그레이드: Codemods
업그레이드: Codemods | Next.js
섹션 제목: “업그레이드: Codemods | Next.js”출처 URL: https://nextjs.org/docs/pages/guides/upgrading/codemods
Codemods
섹션 제목: “Codemods”마지막 업데이트 2026년 2월 20일
Codemod은 코드베이스에서 프로그램적으로 실행되는 변환으로, 모든 파일을 수동으로 확인하지 않아도 대규모 변경을 자동으로 적용할 수 있습니다.
Next.js는 API가 업데이트되거나 사용 중단될 때 Next.js 코드베이스 업그레이드를 돕기 위한 Codemod 변환을 제공합니다.
사용법
섹션 제목: “사용법”터미널에서 프로젝트 폴더로 이동(cd)한 다음 다음을 실행합니다:
터미널
npx @next/codemod <transform> <path><transform>과 <path>를 알맞은 값으로 바꿉니다.
transform- 변환 이름path- 변환할 파일 또는 디렉터리--dry실제 코드를 수정하지 않는 드라이런 수행--print비교용으로 변경된 출력 내용을 표시
업그레이드
섹션 제목: “업그레이드”Next.js, React, React DOM을 업데이트하고 codemod를 자동으로 실행해 Next.js 애플리케이션을 업그레이드합니다.
터미널
npx @next/codemod upgrade [revision]revision(선택 사항): 업그레이드 유형(patch,minor,major), NPM dist 태그(예:latest,canary,rc), 또는 정확한 버전(예:15.0.0)을 지정합니다. 안정 버전의 기본값은minor입니다.--verbose: 업그레이드 과정에서 더 자세한 출력을 표시합니다.
예:
터미널
# 최신 패치로 업그레이드 (예: 16.0.7 -> 16.0.8) npx @next/codemod upgrade patch
# 최신 마이너로 업그레이드 (예: 15.3.7 -> 15.4.8). 기본값입니다. npx @next/codemod upgrade minor
# 최신 메이저로 업그레이드 (예: 15.5.7 -> 16.0.7) npx @next/codemod upgrade major
# 특정 버전으로 업그레이드 npx @next/codemod upgrade 16
# 카나리 릴리스로 업그레이드 npx @next/codemod upgrade canary알아두면 좋아요 :
- 대상 버전이 현재 버전과 같거나 낮으면 명령은 아무 변경 없이 종료됩니다.
- 업그레이드 중 Next.js codemod 적용 여부나 React 업그레이드 시 React 19 codemod 실행 여부를 묻는 프롬프트가 나타날 수 있습니다.
Codemods
섹션 제목: “Codemods”16.0
섹션 제목: “16.0”App Router 페이지와 레이아웃에서 experimental_ppr 라우트 세그먼트 구성 제거
섹션 제목: “App Router 페이지와 레이아웃에서 experimental_ppr 라우트 세그먼트 구성 제거”remove-experimental-ppr
섹션 제목: “remove-experimental-ppr”터미널
npx @next/codemod@latest remove-experimental-ppr .이 codemod는 App Router 페이지와 레이아웃에서 experimental_ppr 라우트 세그먼트 구성을 제거합니다.
app/page.tsx
- export const experimental_ppr = true;안정화된 API에서 unstable_ 접두사 제거
섹션 제목: “안정화된 API에서 unstable_ 접두사 제거”remove-unstable-prefix
섹션 제목: “remove-unstable-prefix”터미널
npx @next/codemod@latest remove-unstable-prefix .이 codemod는 안정화된 API에서 unstable_ 접두사를 제거합니다.
예:
import { unstable_cacheTag as cacheTag } from 'next/cache'
cacheTag()다음으로 변환됩니다:
import { cacheTag } from 'next/cache'
cacheTag()사용 중단된 middleware 규약에서 proxy로 마이그레이션
섹션 제목: “사용 중단된 middleware 규약에서 proxy로 마이그레이션”middleware-to-proxy
섹션 제목: “middleware-to-proxy”터미널
npx @next/codemod@latest middleware-to-proxy .이 codemod는 사용 중단된 middleware 규약을 사용하는 프로젝트를 proxy 규약으로 마이그레이션합니다. 수행 작업:
middleware.<extension>을proxy.<extension>으로 이름 변경(예:middleware.ts→proxy.ts)- 이름이 지정된 export
middleware를proxy로 변경 - Next.js 구성 속성
experimental.middlewarePrefetch를experimental.proxyPrefetch로 변경 - Next.js 구성 속성
experimental.middlewareClientMaxBodySize를experimental.proxyClientMaxBodySize로 변경 - Next.js 구성 속성
experimental.externalMiddlewareRewritesResolve를experimental.externalProxyRewritesResolve로 변경 - Next.js 구성 속성
skipMiddlewareUrlNormalize를skipProxyUrlNormalize로 변경
예:
middleware.ts
import { NextResponse } from 'next/server'
export function middleware() { return NextResponse.next() }다음으로 변환됩니다:
proxy.ts
import { NextResponse } from 'next/server'
export function proxy() { return NextResponse.next() }next lint에서 ESLint CLI로 마이그레이션
섹션 제목: “next lint에서 ESLint CLI로 마이그레이션”next-lint-to-eslint-cli
섹션 제목: “next-lint-to-eslint-cli”터미널
npx @next/codemod@canary next-lint-to-eslint-cli .이 codemod는 next lint를 사용하는 프로젝트를 로컬 ESLint 설정과 함께 ESLint CLI를 사용하도록 마이그레이션합니다. 수행 작업:
- Next.js 권장 구성이 포함된
eslint.config.mjs파일 생성 package.json스크립트를next lint대신eslint .으로 업데이트- 필요한 ESLint 의존성을
package.json에 추가 - 기존 ESLint 구성이 있으면 그대로 유지
예:
package.json
{ "scripts": { "lint": "next lint" } }다음으로 변경됩니다:
package.json
{ "scripts": { "lint": "eslint ." } }그리고 다음 파일을 생성합니다:
eslint.config.mjs
import { dirname } from 'path' import { fileURLToPath } from 'url' import { FlatCompat } from '@eslint/eslintrc'
const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename)
const compat = new FlatCompat({ baseDirectory: __dirname, })
const eslintConfig = [ ...compat.extends('next/core-web-vitals', 'next/typescript'), { ignores: [ 'node_modules/**', '.next/**', 'out/**', 'build/**', 'next-env.d.ts', ], }, ]
export default eslintConfig15.0
섹션 제목: “15.0”App Router 라우트 세그먼트 구성 runtime 값을 experimental-edge에서 edge로 변환
섹션 제목: “App Router 라우트 세그먼트 구성 runtime 값을 experimental-edge에서 edge로 변환”app-dir-runtime-config-experimental-edge
섹션 제목: “app-dir-runtime-config-experimental-edge”참고 : 이 codemod는 App Router 전용입니다.
터미널
npx @next/codemod@latest app-dir-runtime-config-experimental-edge .이 codemod는 Route Segment Config runtime 값 experimental-edge를 edge로 변환합니다.
예:
export const runtime = 'experimental-edge'다음으로 변환됩니다:
export const runtime = 'edge'비동기 Dynamic API로 마이그레이션
섹션 제목: “비동기 Dynamic API로 마이그레이션”기존에 동적 렌더링을 선택해 동기 접근을 지원하던 API가 이제 비동기 방식이 되었습니다. 이 파괴적 변경 사항에 대한 자세한 내용은 업그레이드 가이드에서 확인하세요.
next-async-request-api
섹션 제목: “next-async-request-api”터미널
npx @next/codemod@latest next-async-request-api .이 codemod는 이제 비동기로 전환된 동적 API(next/headers의 cookies(), headers(), draftMode())를 적절하게 await하거나 필요 시 React.use()로 래핑합니다. 자동 마이그레이션이 불가능한 경우 TypeScript 파일이면 타입 캐스트를, 그 외에는 수동 검토 및 업데이트가 필요하다는 주석을 추가합니다.
예:
import { cookies, headers } from 'next/headers' const token = cookies().get('token')
function useToken() { const token = cookies().get('token') return token }
export default function Page() { const name = cookies().get('name') }
function getHeader() { return headers().get('x-foo') }다음으로 변환됩니다:
import { use } from 'react' import { cookies, headers, type UnsafeUnwrappedCookies, type UnsafeUnwrappedHeaders, } from 'next/headers' const token = (cookies() as unknown as UnsafeUnwrappedCookies).get('token')
function useToken() { const token = use(cookies()).get('token') return token }
export default async function Page() { const name = (await cookies()).get('name') }
function getHeader() { return (headers() as unknown as UnsafeUnwrappedHeaders).get('x-foo') }page.js, layout.js, route.js, default.js와 같은 페이지/라우트 항목 또는 generateMetadata / generateViewport API에서 params나 searchParams props에 대한 프로퍼티 접근을 감지하면 동기 호출부를 비동기 함수로 변환하고 프로퍼티 접근을 await하려고 시도합니다. 클라이언트 컴포넌트처럼 비동기로 만들 수 없는 경우 React.use를 사용해 프로미스를 언래핑합니다.
예:
export default function Page({ params, searchParams, }: { params: { slug: string } searchParams: { [key: string]: string | string[] | undefined } }) { const { value } = searchParams if (value === 'foo') { // ... } }
export function generateMetadata({ params }: { params: { slug: string } }) { const { slug } = params return { title: `My Page - ${slug}`, } }다음으로 변환됩니다:
export default async function Page(props: { params: Promise<{ slug: string }> searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) { const searchParams = await props.searchParams const { value } = searchParams if (value === 'foo') { // ... } }
export async function generateMetadata(props: { params: Promise<{ slug: string }> }) { const params = await props.params const { slug } = params return { title: `My Page - ${slug}`, } }알아두면 좋아요: 이 codemod가 수동 개입이 필요할 가능성을 감지했지만 정확한 수정 방법을 결정할 수 없는 경우, 코드에 주석이나 타입 캐스트를 추가해 수동 업데이트가 필요함을 알립니다. 이 주석에는 @next/codemod 접두사가 붙고, 타입 캐스트에는
UnsafeUnwrapped접두사가 붙습니다. 이러한 주석을 명시적으로 제거하기 전까지는 빌드가 실패합니다. 자세히 보기.
NextRequest의 geo 및 ip 프로퍼티를 @vercel/functions로 대체
섹션 제목: “NextRequest의 geo 및 ip 프로퍼티를 @vercel/functions로 대체”next-request-geo-ip
섹션 제목: “next-request-geo-ip”터미널
npx @next/codemod@latest next-request-geo-ip .이 코드를 사용하면 @vercel/functions가 설치되고 NextRequest의 geo 및 ip 속성이 해당 @vercel/functions 기능으로 변환됩니다.
예시:
import type { NextRequest } from 'next/server'
export function GET(req: NextRequest) { const { geo, ip } = req }다음과 같이 변환됩니다:
import type { NextRequest } from 'next/server' import { geolocation, ipAddress } from '@vercel/functions'
export function GET(req: NextRequest) { const geo = geolocation(req) const ip = ipAddress(req) }14.0
섹션 제목: “14.0”ImageResponse 가져오기 마이그레이션
섹션 제목: “ImageResponse 가져오기 마이그레이션”next-og-import
섹션 제목: “next-og-import”터미널
npx @next/codemod@latest next-og-import .이 코드는 동적 OG 이미지 생성 사용을 위해 next/server에서 next/og로 가져오기를 이동하고 변환합니다.
예시:
import { ImageResponse } from 'next/server'다음과 같이 변환됩니다:
import { ImageResponse } from 'next/og'viewport 내보내기 사용
섹션 제목: “viewport 내보내기 사용”metadata-to-viewport-export
섹션 제목: “metadata-to-viewport-export”터미널
npx @next/codemod@latest metadata-to-viewport-export .이 코드는 특정 뷰포트 메타데이터를 viewport 내보내기로 마이그레이션합니다.
예시:
export const metadata = { title: 'My App', themeColor: 'dark', viewport: { width: 1, }, }다음과 같이 변환됩니다:
export const metadata = { title: 'My App', }
export const viewport = { width: 1, themeColor: 'dark', }13.2
섹션 제목: “13.2”기본 제공 글꼴 사용
섹션 제목: “기본 제공 글꼴 사용”built-in-next-font
섹션 제목: “built-in-next-font”터미널
npx @next/codemod@latest built-in-next-font .이 코드는 @next/font 패키지를 제거하고 @next/font 가져오기를 기본 제공 next/font로 변환합니다.
예시:
import { Inter } from '@next/font/google'다음과 같이 변환됩니다:
import { Inter } from 'next/font/google'13.0
섹션 제목: “13.0”Next Image 가져오기 이름 변경
섹션 제목: “Next Image 가져오기 이름 변경”next-image-to-legacy-image
섹션 제목: “next-image-to-legacy-image”터미널
npx @next/codemod@latest next-image-to-legacy-image .기존 Next.js 10, 11, 12 애플리케이션의 next/image 가져오기를 Next.js 13의 next/legacy/image로 안전하게 이름을 변경합니다. 또한 next/future/image를 next/image로 이름을 바꿉니다.
예시:
pages/index.js
import Image1 from 'next/image' import Image2 from 'next/future/image'
export default function Home() { return ( <div> <Image1 src="/test.jpg" width="200" height="300" /> <Image2 src="/test.png" width="500" height="400" /> </div> ) }다음과 같이 변환됩니다:
pages/index.js
// 'next/image' becomes 'next/legacy/image' import Image1 from 'next/legacy/image' // 'next/future/image' becomes 'next/image' import Image2 from 'next/image'
export default function Home() { return ( <div> <Image1 src="/test.jpg" width="200" height="300" /> <Image2 src="/test.png" width="500" height="400" /> </div> ) }새로운 Image 컴포넌트로 마이그레이션
섹션 제목: “새로운 Image 컴포넌트로 마이그레이션”next-image-experimental
섹션 제목: “next-image-experimental”터미널
npx @next/codemod@latest next-image-experimental .next/legacy/image에서 새로운 next/image로 위험도가 높은 마이그레이션을 수행하며, 인라인 스타일을 추가하고 사용되지 않는 props를 제거합니다.
layoutprop을 제거하고style을 추가합니다.objectFitprop을 제거하고style을 추가합니다.objectPositionprop을 제거하고style을 추가합니다.lazyBoundaryprop을 제거합니다.lazyRootprop을 제거합니다.
Link 컴포넌트에서 <a> 태그 제거
섹션 제목: “Link 컴포넌트에서 <a> 태그 제거”new-link
섹션 제목: “new-link”터미널
npx @next/codemod@latest new-link .Link 컴포넌트 안의 <a> 태그를 제거합니다.
예시:
<Link href="/about"> <a>About</a> </Link> // transforms into <Link href="/about"> About </Link>
<Link href="/about"> <a onClick={() => console.log('clicked')}>About</a> </Link> // transforms into <Link href="/about" onClick={() => console.log('clicked')}> About </Link>CRA에서 마이그레이션
섹션 제목: “CRA에서 마이그레이션”cra-to-next
섹션 제목: “cra-to-next”터미널
npx @next/codemod cra-to-nextCreate React App 프로젝트를 Next.js로 마이그레이션하면서 Pages Router와 필요한 구성을 생성해 동작을 맞춥니다. 초기에는 SSR 중 window 사용으로 인한 호환성 깨짐을 막기 위해 클라이언트 사이드 전용 렌더링을 활용하며, 이후 Next.js 고유 기능을 점진적으로 도입할 수 있습니다.
이 변환에 대한 피드백은 이 토론에 공유해 주세요.
React 가져오기 추가
섹션 제목: “React 가져오기 추가”add-missing-react-import
섹션 제목: “add-missing-react-import”터미널
npx @next/codemod add-missing-react-importReact를 가져오지 않는 파일에 가져오기를 추가하여 새로운 React JSX 변환이 동작하도록 합니다.
예시:
my-component.js
export default class Home extends React.Component { render() { return <div>Hello World</div> } }다음과 같이 변환됩니다:
my-component.js
import React from 'react' export default class Home extends React.Component { render() { return <div>Hello World</div> } }익명 컴포넌트를 명명된 컴포넌트로 변환
섹션 제목: “익명 컴포넌트를 명명된 컴포넌트로 변환”name-default-component
섹션 제목: “name-default-component”터미널
npx @next/codemod name-default-component버전 9 이상.
익명 컴포넌트를 명명된 컴포넌트로 변환하여 Fast Refresh와 함께 동작하도록 합니다.
예시:
my-component.js
export default function () { return <div>Hello World</div> }다음과 같이 변환됩니다:
my-component.js
export default function MyComponent() { return <div>Hello World</div> }컴포넌트 이름은 파일 이름을 기반으로 카멜 케이스로 지정되며, 화살표 함수에도 동일하게 작동합니다.
참고: 기본 제공 AMP 지원과 이 코드는 Next.js 16에서 제거되었습니다.
AMP HOC를 페이지 구성으로 변환
섹션 제목: “AMP HOC를 페이지 구성으로 변환”withamp-to-config
섹션 제목: “withamp-to-config”터미널
npx @next/codemod withamp-to-configwithAmp HOC를 Next.js 9 페이지 구성으로 변환합니다.
예시:
// Before import { withAmp } from 'next/amp'
function Home() { return <h1>My AMP Page</h1> }
export default withAmp(Home) // After export default function Home() { return <h1>My AMP Page</h1> }
export const config = { amp: true, }withRouter 사용
섹션 제목: “withRouter 사용”url-to-withrouter
섹션 제목: “url-to-withrouter”터미널
npx @next/codemod url-to-withrouter더 이상 사용되지 않는 최상위 페이지의 자동 주입 url 속성을 withRouter와 그가 주입하는 router 속성으로 변환합니다. 자세한 내용: https://nextjs.org/docs/messages/url-deprecated
예시:
변환 전
import React from 'react' export default class extends React.Component { render() { const { pathname } = this.props.url return <div>Current pathname: {pathname}</div> } }변환 후
import React from 'react' import { withRouter } from 'next/router' export default withRouter( class extends React.Component { render() { const { pathname } = this.props.router return <div>Current pathname: {pathname}</div> } } )이 사례를 포함한 모든 변환(및 테스트)은 __testfixtures__ 디렉터리에 있습니다.
보내기