요즘 냉장고 재료 관리 프로젝트를 진행 중이다.
냉장고에 있는 재료를 등록하고, 수정하고, 삭제할 수 있는 CRUD API를 Next.js(App Router) 기반으로 구현하고 있는데, 생각지도 못한 에러를 마주했다. 요청은 정상적으로 처리됐지만 서버 콘솔에 계속 에러 로그가 찍히는 문제였다.
ingredients CRUD API 개발 중:
- POST: 재료 추가
- GET: 재료 조회
- PATCH: 재료 수정
- DELETE: 재료 삭제
특히 PATCH와 DELETE 요청은 클라이언트 측에서 정상적으로 200 응답을 반환했지만, 서버 로그에는 에러 메시지가 남았다.
발생 오류
Error: Route "/api/ingredients/[id]" used params.id.
params should be awaited before using its properties.
Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
at PATCH (app/api/ingredients/[id]/route.ts:23:31)
21 | ) {
22 | try {
23 | const id = parseId(params.id);
| ^
24 | const body = await req.json();
문제 코드
export async function PATCH(
req: Request,
{ params }: { params: { id: string } }
) {
try {
const id = parseId(params.id); // ❌ 에러 발생 지점
const body = await req.json();
// ...
}
}
겉으로 보기엔 아무 문제 없어 보였는데, params.id에서 바로 터졌다.
원인 분석

오류 메시지에 달린 Next.js 공식 문서 링크를 열어보니 이유가 나왔다.
Next.js 15부터는 동적 라우트의 params 객체가 Promise로 제공되도록 변경된 것.
예전처럼 바로 params.id로 접근하면 안 되고, 먼저 await해서 값을 꺼내야 한다.
해결 방법
params를 Promise 타입으로 선언하고, 내부에서 await 처리하는 방식으로 바꿔야 했다.
수정 코드
export async function PATCH(
req: Request,
{ params }: { params: Promise<{ id: string }> }
) {
try {
const { id } = await params; // ✅ await 추가
const parsedId = parseId(id);
const body = await req.json();
// ...
}
}
회고
- Next.js 15에서는 동적 라우트의 params가 Promise라는 걸 명심해야 한다.
- 공식 문서에서 제공하는 에러 메시지를 무시하지 않고 링크를 확인하는 게 시간을 아낀다.
- CRUD 전체에 공통적으로 영향을 주는 부분이라 한 번에 전체 API를 점검해야 한다.
냉장고 프로젝트를 하면서 이런 변경사항을 직접 겪어보니, 버전 업그레이드 시에는 항상 Breaking Changes를 먼저 확인해야겠다는 교훈을 얻었다. 작은 차이 같지만, 팀 단위로 개발할 때는 반드시 공유해두는 게 중요하다.
