콘텐츠로 이동

업그레이드: Codemods

Source URL: https://nextjs.org/docs/app/guides/upgrading/codemods

Copy page

마지막 업데이트 2026년 2월 20일

Codemod은 코드베이스에 대해 프로그램 방식으로 실행되는 변환입니다. 이를 통해 모든 파일을 수동으로 훑어보지 않고도 대규모 변경을 자동으로 적용할 수 있습니다.

Next.js는 API가 업데이트되거나 사용 중단될 때 Next.js 코드베이스를 업그레이드하는 데 도움이 되는 Codemod 변환을 제공합니다.

터미널에서 프로젝트 폴더로 이동(cd)한 뒤 다음 명령을 실행하세요:

Terminal

npx @next/codemod <transform> <path>

<transform><path>를 적절한 값으로 바꿔 입력합니다.

  • transform - 변환 이름
  • path - 변환할 파일 또는 디렉터리
  • --dry 코드 편집 없이 드라이런 수행
  • --print 비교를 위해 변경된 출력을 표시

Next.js, React, React DOM을 업데이트하면서 codemod를 자동 실행해 Next.js 애플리케이션을 업그레이드합니다.

Terminal

npx @next/codemod upgrade [revision]
  • revision(선택 사항): 업그레이드 유형(patch, minor, major), NPM dist 태그(예: latest, canary, rc), 또는 정확한 버전(예: 15.0.0)을 지정합니다. 안정 버전에서는 기본값이 minor입니다.
  • --verbose: 업그레이드 과정에서 더 자세한 출력을 표시합니다.

예시:

Terminal

# 최신 패치로 업그레이드(예: 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
# canary 릴리스로 업그레이드
npx @next/codemod upgrade canary

알아두면 좋아요 :

  • 대상 버전이 현재 버전과 같거나 더 낮으면 명령은 변경 없이 종료됩니다.
  • 업그레이드 중에 적용할 Next.js codemod를 선택하거나 React를 업그레이드할 때 React 19 codemod 실행 여부를 묻는 프롬프트가 나타날 수 있습니다.

App Router 페이지와 레이아웃에서 experimental_ppr Route Segment Config 제거

섹션 제목: “App Router 페이지와 레이아웃에서 experimental_ppr Route Segment Config 제거”

Terminal

npx @next/codemod@latest remove-experimental-ppr .

이 codemod는 App Router 페이지와 레이아웃에서 experimental_ppr Route Segment Config를 제거합니다.

app/page.tsx

- export const experimental_ppr = true;

안정화된 API에서 unstable_ 접두사 제거

섹션 제목: “안정화된 API에서 unstable_ 접두사 제거”

Terminal

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로 마이그레이션”

Terminal

npx @next/codemod@latest middleware-to-proxy .

이 codemod는 사용 중단된 middleware 규칙을 proxy 규칙으로 마이그레이션합니다. 작업 내용은 다음과 같습니다.

  • middleware.<extension>proxy.<extension>으로 이름 변경(예: middleware.tsproxy.ts)
  • 이름이 지정된 export middlewareproxy로 변경
  • Next.js 설정 속성 experimental.middlewarePrefetchexperimental.proxyPrefetch로 변경
  • Next.js 설정 속성 experimental.middlewareClientMaxBodySizeexperimental.proxyClientMaxBodySize로 변경
  • Next.js 설정 속성 experimental.externalMiddlewareRewritesResolveexperimental.externalProxyRewritesResolve로 변경
  • Next.js 설정 속성 skipMiddlewareUrlNormalizeskipProxyUrlNormalize로 변경

예시:

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로 마이그레이션”

Terminal

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 eslintConfig

App Router Route Segment Config runtime 값을 experimental-edge에서 edge로 변환

섹션 제목: “App Router Route Segment Config runtime 값을 experimental-edge에서 edge로 변환”

참고 : 이 codemod는 App Router 전용입니다.

Terminal

npx @next/codemod@latest app-dir-runtime-config-experimental-edge .

이 codemod는 Route Segment Config runtimeexperimental-edgeedge로 변환합니다.

예시:

export const runtime = 'experimental-edge'

변환 후:

export const runtime = 'edge'

비동기 Dynamic API로 마이그레이션

섹션 제목: “비동기 Dynamic API로 마이그레이션”

동적 렌더링을 선택했던 API 중 동기 접근을 지원하던 항목이 이제 비동기로 전환되었습니다. 이 파괴적 변경 사항에 대한 자세한 내용은 업그레이드 가이드에서 확인할 수 있습니다.

Terminal

npx @next/codemod@latest next-async-request-api .

이 codemod는 이제 비동기화된 동적 API(next/headerscookies(), 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하도록 시도합니다. 비동기로 전환할 수 없는 경우(예: Client Component)에는 React.use를 사용해 프로미스를 언랩합니다.

예시:

page.tsx
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}`,
}
}

변환 후:

page.tsx
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 접두사를 사용합니다. 이 주석을 명시적으로 제거하지 않으면 빌드가 오류를 발생시킵니다. 더 알아보기.

NextRequestgeoip 속성을 @vercel/functions로 교체

섹션 제목: “NextRequest의 geo 및 ip 속성을 @vercel/functions로 교체”

터미널

npx @next/codemod@latest next-request-geo-ip .

이 코드는 @vercel/functions를 설치하고 NextRequestgeo, 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)
}

ImageResponse 임포트 마이그레이션

섹션 제목: “ImageResponse 임포트 마이그레이션”

터미널

npx @next/codemod@latest next-og-import .

이 코드는 Dynamic OG Image Generation 사용을 위해 next/server에서 next/og로 임포트를 이동하고 변환합니다.

예:

import { ImageResponse } from 'next/server'

아래와 같이 변환됩니다:

import { ImageResponse } from 'next/og'

터미널

npx @next/codemod@latest metadata-to-viewport-export .

이 코드는 특정 viewport 메타데이터를 viewport export로 마이그레이션합니다.

예:

export const metadata = {
title: 'My App',
themeColor: 'dark',
viewport: {
width: 1,
},
}

아래와 같이 변환됩니다:

export const metadata = {
title: 'My App',
}
export const viewport = {
width: 1,
themeColor: 'dark',
}

터미널

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'

터미널

npx @next/codemod@latest next-image-to-legacy-image .

Next.js 10, 11, 12 애플리케이션의 next/image 임포트를 Next.js 13에서 next/legacy/image로 안전하게 변경합니다. 또한 next/future/imagenext/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 컴포넌트로 마이그레이션”

터미널

npx @next/codemod@latest next-image-experimental .

next/legacy/image에서 새로운 next/image로 위험하게 마이그레이션하며 인라인 스타일을 추가하고 사용되지 않는 props를 제거합니다.

  • layout prop을 제거하고 style을 추가합니다.
  • objectFit prop을 제거하고 style을 추가합니다.
  • objectPosition prop을 제거하고 style을 추가합니다.
  • lazyBoundary prop을 제거합니다.
  • lazyRoot prop을 제거합니다.

터미널

npx @next/codemod@latest new-link .

Link Components 내부의 <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>

터미널

npx @next/codemod cra-to-next

Create React App 프로젝트를 Next.js로 마이그레이션하며, Pages Router와 동일한 동작을 위한 필수 설정을 생성합니다. 초기에는 SSR 중 window 사용으로 호환성이 깨지지 않도록 클라이언트 전용 렌더링을 활용하며, 이를 무중단으로 활성화해 점진적으로 Next.js 고유 기능을 도입할 수 있습니다.

이 변환에 대한 피드백은 이 토론에 공유해 주세요.

터미널

npx @next/codemod add-missing-react-import

React를 임포트하지 않은 파일에 임포트를 추가해 새로운 React JSX transform이 동작하도록 합니다.

예:

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>
}
}

익명 컴포넌트를 명명된 컴포넌트로 변환

섹션 제목: “익명 컴포넌트를 명명된 컴포넌트로 변환”

터미널

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>
}

컴포넌트는 파일 이름을 기반으로 camelCase 이름을 가지며, 화살표 함수에서도 작동합니다.

참고: 기본 제공 AMP 지원과 이 codemod는 Next.js 16에서 제거되었습니다.

터미널

npx @next/codemod withamp-to-config

withAmp 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,
}

터미널

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__ 디렉터리에서 확인할 수 있습니다.

보내기