업그레이드: Codemods
업그레이드: Codemods | Next.js
섹션 제목: “업그레이드: Codemods | Next.js”Source URL: https://nextjs.org/docs/app/guides/upgrading/codemods
Copy page
Codemods
섹션 제목: “Codemods”마지막 업데이트 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 실행 여부를 묻는 프롬프트가 나타날 수 있습니다.
Codemods
섹션 제목: “Codemods”16.0
섹션 제목: “16.0”App Router 페이지와 레이아웃에서 experimental_ppr Route Segment Config 제거
섹션 제목: “App Router 페이지와 레이아웃에서 experimental_ppr Route Segment Config 제거”remove-experimental-ppr
섹션 제목: “remove-experimental-ppr”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_ 접두사 제거”remove-unstable-prefix
섹션 제목: “remove-unstable-prefix”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로 마이그레이션”middleware-to-proxy
섹션 제목: “middleware-to-proxy”Terminal
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”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 eslintConfig15.0
섹션 제목: “15.0”App Router Route Segment Config runtime 값을 experimental-edge에서 edge로 변환
섹션 제목: “App Router Route Segment Config runtime 값을 experimental-edge에서 edge로 변환”app-dir-runtime-config-experimental-edge
섹션 제목: “app-dir-runtime-config-experimental-edge”참고 : 이 codemod는 App Router 전용입니다.
Terminal
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”Terminal
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하도록 시도합니다. 비동기로 전환할 수 없는 경우(예: Client Component)에는 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 .이 코드는 Dynamic OG Image Generation 사용을 위해 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 메타데이터를 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', }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 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>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 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> } }익명 컴포넌트를 명명된 컴포넌트로 변환
섹션 제목: “익명 컴포넌트를 명명된 컴포넌트로 변환”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> }컴포넌트는 파일 이름을 기반으로 camelCase 이름을 가지며, 화살표 함수에서도 작동합니다.
참고: 기본 제공 AMP 지원과 이 codemod는 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__ 디렉터리에서 확인할 수 있습니다.
보내기