| name | jikime-framework-nextjs@15 |
| description | Next.js 15 upgrade guide with breaking changes from 14. Async params, Turbopack stable, fetch caching changes. |
| tags | ["framework","nextjs","version","async-params","turbopack","react-19"] |
| triggers | {"keywords":["nextjs 15","next.js 15","async params","turbopack","react 19"],"phases":["run"],"agents":["frontend"],"languages":["typescript"]} |
| progressive_disclosure | {"enabled":true,"level1_tokens":"~100","level2_tokens":"~2022"} |
| type | version |
| framework | nextjs |
| version | 15 |
| previous_version | 14 |
| user-invocable | false |
Next.js 15 Upgrade Guide (from 14)
Next.js 14에서 15로 업그레이드 시 필요한 breaking changes와 마이그레이션 패턴을 정의합니다.
Version Info
| 항목 | 값 |
|---|
| Version | 15.0.0 ~ 15.x |
| Release Date | October 2024 |
| Node.js | 18.18+ (20+ recommended) |
| React | 19 RC |
Base Conventions (from Next.js 14)
다음 규칙은 Next.js 14부터 동일하게 적용됩니다. 상세 내용은 jikime-framework-nextjs@14를 참조하세요.
| 규칙 | 요약 |
|---|
| 프로젝트 구조 | src/app/ 기반 App Router, src/app/api/[endpoint]/route.ts API 라우트 |
| 네이밍 규칙 | 폴더/파일: kebab-case, 컴포넌트 export: PascalCase |
| UI 라이브러리 | shadcn/ui 필수 사용, lucide-react 아이콘 |
| 스타일링 | Tailwind CSS + CSS variables 기반 테마 |
Project Initialization (Next.js 15)
새 프로젝트를 시작할 때는 다음 순서로 생성합니다:
npx create-next-app@15 my-app --typescript --tailwind --eslint --app --src-dir
cd my-app
npx shadcn@latest init
npx shadcn@latest add button card input form table
CRITICAL: npx shadcn@latest init은 기존 Next.js 프로젝트에서만 실행합니다. 프로젝트 생성은 반드시 create-next-app으로 먼저 해야 합니다.
Breaking Changes Summary
| 변경 사항 | 영향도 | 자동 수정 |
|---|
params/searchParams async | 🔴 High | codemod |
| fetch cache default 변경 | 🟡 Medium | Manual |
NextRequest.geo/ip 제거 | 🟡 Medium | Manual |
next/dynamic ssr 옵션 | 🟢 Low | codemod |
| Runtime config 제거 | 🟢 Low | Manual |
1. Async Params (CRITICAL)
Before (Next.js 14)
type Props = {
params: { slug: string }
searchParams: { [key: string]: string | undefined }
}
export default function PostPage({ params, searchParams }: Props) {
const { slug } = params
const { sort } = searchParams
return <div>Post: {slug}</div>
}
export async function generateMetadata({ params }: Props) {
const post = await getPost(params.slug)
return { title: post.title }
}
After (Next.js 15)
type Props = {
params: Promise<{ slug: string }>
searchParams: Promise<{ [key: string]: string | undefined }>
}
export default async function PostPage({ params, searchParams }: Props) {
const { slug } = await params
const { sort } = await searchParams
return <div>Post: {slug}</div>
}
export async function generateMetadata({ params }: Props) {
const { slug } = await params
const post = await getPost(slug)
return { title: post.title }
}
Layout Props
type LayoutProps = {
children: React.ReactNode
params: { slug: string }
}
type LayoutProps = {
children: React.ReactNode
params: Promise<{ slug: string }>
}
export default async function Layout({ children, params }: LayoutProps) {
const { slug } = await params
return <div>{children}</div>
}
Codemod
npx @next/codemod@canary next-async-request-api .
2. Fetch Caching Default Change
Before (Next.js 14)
const data = await fetch('https://api.example.com/data')
After (Next.js 15)
const data = await fetch('https://api.example.com/data')
const data = await fetch('https://api.example.com/data', {
cache: 'force-cache'
})
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 }
})
Migration Strategy
const data = await fetch(url, { cache: 'force-cache' })
export const fetchCache = 'default-cache'
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
static: 180,
}
}
}
3. NextRequest Changes
geo/ip Removed
export function middleware(request: NextRequest) {
const { geo, ip } = request
const country = geo?.country
}
export function middleware(request: NextRequest) {
const country = request.headers.get('x-vercel-ip-country')
const ip = request.headers.get('x-forwarded-for')
import { geolocation, ipAddress } from '@vercel/functions'
const geo = geolocation(request)
const ip = ipAddress(request)
}
4. Dynamic Import Changes
ssr Option Renamed
const Component = dynamic(() => import('./component'), {
ssr: false
})
const Component = dynamic(() => import('./component'), {
ssr: false
})
import dynamic from 'next/dynamic'
const Component = dynamic(() => import('./component'), {
loading: () => <p>Loading...</p>
})
5. Runtime Config Removed
const nextConfig = {
serverRuntimeConfig: {
mySecret: 'secret'
},
publicRuntimeConfig: {
apiUrl: 'https://api.example.com'
}
}
import getConfig from 'next/config'
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
MY_SECRET=secret
NEXT_PUBLIC_API_URL=https:
const apiUrl = process.env.NEXT_PUBLIC_API_URL
6. Turbopack (Stable for Dev)
next dev --turbo
{
"scripts": {
"dev": "next dev --turbo"
}
}
next.config.ts Support
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
}
export default nextConfig
7. React 19 Compatibility
New Hooks
'use client'
import { useFormStatus, useFormState } from 'react-dom'
import { useOptimistic, use } from 'react'
function SubmitButton() {
const { pending } = useFormStatus()
return <button disabled={pending}>Submit</button>
}
function TodoList({ todos }) {
const [optimisticTodos, addOptimisticTodo] = useOptimistic(
todos,
(state, newTodo) => [...state, newTodo]
)
}
Migration Checklist
Automated (Codemod)
Manual Review
Testing
Upgrade Commands
npm install next@15 react@19 react-dom@19
npx @next/codemod@canary next-async-request-api .
npm install -D @types/react@19 @types/react-dom@19
npm run build
npm run dev
Rollback Plan
If issues occur:
npm install next@14 react@18 react-dom@18
git checkout .
Related Skills
| 스킬 | 용도 |
|---|
jikime-framework-nextjs@14 | Next.js 14 App Router 기본 패턴, 프로젝트 구조, 네이밍 규칙, shadcn/ui |
jikime-framework-nextjs@16 | Next.js 16 업그레이드 가이드 ('use cache', PPR, updateTag) |
jikime-platform-vercel | Vercel 배포, Edge Functions, ISR |
jikime-library-shadcn | shadcn/ui 컴포넌트 라이브러리 (Next.js 필수) |
Version: 1.1.0
Last Updated: 2026-01-23
Upgrade Path: Next.js 15 → 16: See jikime-framework-nextjs@16