Next.js 16.3.0-canary.106은 운영자가 바로 기능을 바꿔야 하는 대형 릴리스라기보다, useCache 관련 deprecation 경고와 hybrid not-found 수정이 프로젝트 유지보수에 어떤 신호를 주는지 확인해야 하는 canary 릴리스로 볼 수 있습니다. 이 글은 경고를 해석하는 방법, 영향을 받을 수 있는 라우팅 흐름, 업그레이드 전 점검 순서를 실무 관점에서 정리합니다.- Next.js 16.3.0-canary.106에서 확인할 변경점
- useCache deprecation 경고의 의미
- hybrid not-found 수정이 중요한 이유
- 실무 업그레이드 점검 순서
- 적용 여부를 결정하는 기준
- 정리
Next.js 16.3.0-canary.106에서 확인할 변경점

Next.js 16.3.0-canary.106을 볼 때 가장 먼저 구분해야 할 것은 이 버전이 stable 릴리스가 아니라 canary 채널이라는 점입니다. canary는 곧바로 운영 반영을 전제로 읽기보다, 앞으로 바뀔 동작과 경고를 미리 확인하는 채널에 가깝습니다. 따라서 이번 변경도 “지금 모든 코드를 바꿔야 한다”는 신호가 아니라, 공식 태그와 릴리스 노트에서 해당 변경이 실제로 포함됐는지 대조한 뒤 “현재 프로젝트가 향후 변경에 얼마나 준비되어 있는지 확인하라”는 신호로 읽는 편이 안전합니다.
canary 릴리스를 읽을 때 주의할 점
Next.js의 canary 버전은 프레임워크 내부 동작, 실험적 API, 경고 메시지, 라우팅 처리 방식이 비교적 빠르게 바뀔 수 있습니다. 특히 App Router, Server Component, 캐시 계층, not-found 처리처럼 빌드 시점과 런타임 동작이 맞물리는 영역은 작은 수정도 실제 화면에서는 다르게 보일 수 있습니다. 그래서 릴리스 노트를 읽을 때는 변경 문장만 보지 말고, 내 프로젝트에서 해당 흐름이 어디에 걸려 있는지 함께 봐야 합니다.
이번 글에서 다루는 범위
이 글은 두 가지에 집중합니다. 첫째, useCache 관련 deprecation 경고가 실무 코드에서 어떤 의미를 갖는지 설명합니다. 둘째, hybrid not-found 수정이 App Router 기반 서비스의 404 처리와 어떤 관련이 있는지 정리합니다. 세부 내부 구현을 단정하기보다, 실제 프로젝트에서 확인해야 할 로그, 라우트, 테스트 시나리오를 중심으로 접근합니다.
공식 변경 근거를 확인하는 방법
이처럼 특정 canary 버전을 다룰 때는 글을 발행하기 전에 vercel/next.js 저장소의 릴리스, 태그, 비교 화면을 함께 확인해야 합니다. 확인 기준일을 문서에 남기고, useCache deprecation과 hybrid not-found가 같은 태그에 포함된 변경인지, 아니면 인접한 canary나 preview 브랜치에서 관찰한 변경인지 구분해야 합니다. PR 번호나 커밋 해시를 확인할 수 있다면 운영 판단 문장에는 그 근거를 함께 붙이는 편이 좋습니다.
useCache deprecation 경고의 의미
deprecation 경고는 보통 “즉시 삭제”가 아니라 “앞으로 권장되지 않을 수 있으니 의존성을 줄이라”는 신호입니다. useCache 관련 경고도 같은 방식으로 해석하는 것이 좋습니다. 중요한 것은 경고가 발생했다는 사실 자체보다, 경고가 어느 코드 경로에서 발생하는지, 빌드 로그에서만 보이는지, 개발 서버에서만 보이는지, 특정 라우트 접근 시 반복되는지 확인하는 일입니다.
deprecation 경고가 말하는 것
useCache가 직접 작성한 애플리케이션 코드에 있는지, 아니면 의존 패키지 내부에서 호출되는지에 따라 대응 방식은 달라집니다. 직접 사용 중이라면 대체 API나 권장 패턴을 검토해야 하고, 외부 패키지에서 발생한다면 패키지 버전, 이슈, 릴리스 계획을 확인해야 합니다. 경고를 없애는 것보다 먼저 경고의 소유권을 분리하는 것이 중요합니다.
Warning: useCache is deprecated and may be removed in a future version.
Route: /products/[slug]
Source: app/products/[slug]/page.tsx
위와 같은 로그가 보인다면 먼저 app/products/[slug]/page.tsx에서 직접 useCache를 호출하는지 확인합니다. 직접 호출이 없다면 해당 파일에서 사용하는 데이터 유틸, 서버 액션, CMS 클라이언트, 내부 공용 함수까지 범위를 넓혀야 합니다. 예를 들어 getProduct, fetchProductDetail, createCachedClient 같은 함수가 내부에서 캐시 API를 감싸고 있을 수 있습니다.
당장 확인해야 할 코드 위치
점검 우선순위는 명확합니다. 먼저 app 디렉터리의 라우트 파일을 확인하고, 다음으로 lib, services, utils 같은 공용 모듈을 확인합니다. 마지막으로 외부 패키지에서 경고가 발생하는지 봅니다. 특히 page.tsx, layout.tsx, route.ts, generateMetadata, generateStaticParams처럼 프레임워크가 직접 호출하는 진입점은 경고가 사용자 화면과 빌드 결과에 영향을 줄 가능성이 큽니다.
app/**/page.tsx에서 데이터 로딩 함수가 어떤 캐시 계층을 쓰는지 확인합니다.app/**/layout.tsx에서 전역 데이터, 인증 상태, 설정 값을 캐싱하는지 확인합니다.lib/cache.ts,lib/fetcher.ts,services/*.ts에서useCache를 감싼 래퍼가 있는지 확인합니다.node_modules에서 발생한 경고라면 직접 수정보다 패키지 업데이트 가능성을 먼저 봅니다.
운영 반영 전 판단 기준
deprecation 경고가 있어도 서비스가 즉시 깨지는 것은 아닐 수 있습니다. 하지만 canary에서 이미 경고가 노출된다면, 다음 stable 또는 이후 메이저 변경에서 실제 제거로 이어질 가능성을 염두에 두어야 합니다. 운영 반영 전에는 경고 횟수만 세지 말고, 해당 경고가 공식 릴리스 노트의 변경 항목과 같은 원인인지 대조해야 합니다. 애플리케이션 코드에서 발생한 경고라면 대체 패턴 검토로 이어지고, 의존 패키지에서 발생한 경고라면 패키지 이슈나 업스트림 PR 확인이 먼저입니다.
hybrid not-found 수정이 중요한 이유

hybrid not-found 수정은 이름만 보면 좁은 변경처럼 보이지만, 실제 서비스에서는 꽤 중요한 영역에 닿을 수 있습니다. App Router에서 notFound는 단순히 404 페이지를 보여주는 기능이 아니라, 정적 생성, 동적 렌더링, 중첩 라우트, 세그먼트별 not-found.tsx 구성과 함께 작동합니다. 이 흐름이 어긋나면 존재하지 않는 콘텐츠가 잘못 렌더링되거나, 반대로 정상 콘텐츠가 404처럼 처리될 수 있습니다.
hybrid 라우트에서 not-found가 까다로운 이유
hybrid라는 표현은 대체로 정적 특성과 동적 특성이 섞인 상황을 떠올리게 합니다. 예를 들어 일부 상품 상세 페이지는 generateStaticParams로 미리 생성하고, 새 상품은 요청 시 동적으로 처리할 수 있습니다. 여기에 notFound, dynamicParams, 데이터 캐시, 재검증 정책이 겹치면 특정 경로가 “없는 페이지”인지 “아직 생성되지 않은 페이지”인지 판단하는 시점이 중요해집니다.
import { notFound } from "next/navigation";
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = await getPost(slug);
if (!post) {
notFound();
}
return <ArticleView post={post} />;
}
위 예시에서 notFound는 데이터가 없을 때 호출됩니다. 하지만 실제 프로젝트에서는 getPost가 캐시된 응답을 반환할 수 있고, generateStaticParams가 일부 slug만 제공할 수 있으며, 상위 layout.tsx가 별도의 데이터를 먼저 읽을 수도 있습니다. 이 때문에 not-found.tsx가 어느 세그먼트에서 렌더링되는지, 응답 상태가 어떻게 정해지는지, 이전 캐시가 남아 있지 않은지 확인해야 합니다.
수정으로 기대할 수 있는 동작
hybrid not-found 수정에서 기대할 수 있는 핵심은 혼합 렌더링 조건에서 notFound 처리가 더 일관되게 동작하는 것입니다. 다만 실제 영향 범위는 프로젝트 구조에 따라 달라집니다. 동적 상세 페이지, 다국어 라우트, CMS 기반 콘텐츠 페이지, 권한에 따라 존재 여부가 달라지는 페이지는 모두 확인 대상입니다. 특히 app/[locale]/blog/[slug]/page.tsx처럼 세그먼트가 여러 단계인 구조에서는 상위와 하위의 not-found.tsx 중 어느 화면이 표시되는지 눈으로 확인하는 것이 좋습니다.
회귀 가능성이 있는 화면
회귀 테스트가 필요한 화면은 대체로 “정상 경로와 비정상 경로가 비슷하게 생긴 곳”입니다. 예를 들어 삭제된 상품, 비공개 게시글, 잘못된 지역 코드, 만료된 이벤트, 권한 없는 문서 상세 페이지가 해당합니다. 이런 화면은 데이터가 없어서 404가 되어야 하는지, 권한 문제로 403에 가까운 안내가 필요한지, 로그인 화면으로 보내야 하는지 정책이 섞이기 쉽습니다. notFound는 편리하지만 모든 실패 상태를 대신하는 도구는 아닙니다.
실무 업그레이드 점검 순서
Next.js 16.3.0-canary.106을 시험하려면 운영 브랜치에 바로 올리기보다 별도 브랜치와 재현 가능한 환경을 먼저 준비하는 편이 좋습니다. 핵심은 업그레이드 자체가 아니라 업그레이드 전후 차이를 비교할 수 있는 상태를 만드는 것입니다. 경고 로그, 라우팅 결과, 빌드 산출물, 주요 페이지의 응답 상태를 같은 기준으로 남겨야 합니다.
경고 로그 확인
먼저 개발 서버와 빌드에서 경고가 다르게 나타나는지 확인합니다. next dev에서는 보이지 않던 경고가 next build에서만 보일 수 있고, 반대로 특정 페이지를 브라우저로 접근해야 재현되는 경고도 있습니다. 가능하면 로컬에서 한 번, CI에서 한 번 확인해 환경 차이를 줄이는 것이 좋습니다.
npm install next@16.3.0-canary.106
npm run build
npm run test
npm run lint
명령 실행 후에는 useCache, deprecated, not-found, notFound, cache 같은 문자열을 기준으로 로그를 분류합니다. 모든 경고를 즉시 수정하려고 하기보다, 애플리케이션 코드에서 발생한 경고와 외부 의존성에서 발생한 경고를 나누는 것이 먼저입니다.
라우트별 404 테스트
404 테스트는 단순히 존재하지 않는 URL 하나를 열어보는 것으로는 부족합니다. 정상 데이터가 있는 상세 페이지, 삭제된 데이터의 상세 페이지, 형식은 맞지만 실제 데이터가 없는 slug, 형식 자체가 잘못된 경로를 각각 확인해야 합니다. 또한 not-found.tsx가 루트에 있는지, 세그먼트 내부에 있는지에 따라 표시되는 화면이 달라질 수 있으므로 라우트 그룹별로 나누어 테스트하는 편이 좋습니다.
- 정상
slug에서 기대한 콘텐츠와 상태 코드가 유지되는지 확인합니다. - 없는
slug에서 올바른not-found.tsx가 표시되는지 확인합니다. generateStaticParams에 없는 값이 동적 처리되는지, 또는404가 되는지 확인합니다.- 캐시 삭제 또는 재검증 후에도 같은 결과가 나오는지 확인합니다.
CI와 배포 전 검증
CI에서는 경고를 단순 출력으로 남길지, 특정 경고를 실패 조건으로 볼지 결정해야 합니다. canary 검증 단계에서는 모든 경고를 실패로 만들면 실험이 어려울 수 있습니다. 대신 useCache 경고 개수, 발생 파일, 신규 경고 여부를 기록해 추세를 보는 방식이 현실적입니다. 배포 전에는 프리뷰 환경에서 404 관련 URL을 직접 확인하고, 로그 수집 도구에서 응답 상태가 의도대로 기록되는지 확인합니다. 이때 릴리스 확인 기준일, 비교한 태그, 관련 PR 번호를 작업 기록에 남기면 나중에 같은 경고가 재등장했을 때 원인 추적이 쉬워집니다.
적용 여부를 결정하는 기준
canary 버전을 적용할지 말지는 “새 버전이 나왔는가”가 아니라 “지금 이 변경을 검증할 이유가 있는가”로 결정하는 편이 좋습니다. 특정 버그 수정이 현재 서비스의 문제와 직접 연결되어 있다면 시험할 가치가 있습니다. 반대로 현재 서비스가 안정적으로 동작하고 있고, 이번 변경이 직접적인 문제를 해결하지 않는다면 stable 릴리스를 기다리는 것이 더 나을 수 있습니다.
canary를 써도 되는 상황
canary 적용이 합리적인 상황은 비교적 분명합니다. 이미 not-found 처리에서 재현 가능한 문제가 있고, 해당 수정이 그 문제와 관련되어 보이며, 프리뷰 환경과 회귀 테스트가 준비되어 있다면 검토할 수 있습니다. 또한 프레임워크 변경을 빠르게 추적해야 하는 플랫폼 팀이나 디자인 시스템 팀이라면 useCache 경고를 미리 파악하는 목적만으로도 별도 브랜치에서 테스트할 가치가 있습니다.
stable을 기다리는 것이 나은 상황
반대로 운영 서비스가 민감하고, App Router의 라우팅 테스트가 충분하지 않거나, 캐시 계층이 복잡한데 소유자가 불분명하다면 stable을 기다리는 편이 낫습니다. 특히 결제, 인증, 관리자 승인, 권한 기반 문서 접근처럼 실패 상태가 곧 사용자 신뢰와 연결되는 화면에서는 작은 라우팅 차이도 비용이 큽니다. 이 경우에는 canary를 운영에 넣기보다 테스트 브랜치에서 경고와 라우트 결과만 수집하는 방식이 더 적절합니다.
정리
Next.js 16.3.0-canary.106에서 볼 핵심은 useCache 관련 deprecation 경고와 hybrid not-found 수정입니다. useCache 경고는 당장 장애를 뜻한다기보다 향후 변경에 대비해 캐시 사용 지점을 확인하라는 신호로 보는 것이 좋습니다. hybrid not-found 수정은 정적 생성과 동적 렌더링이 섞인 라우트에서 notFound 처리가 더 예측 가능해질 수 있다는 점에서 중요합니다.
실무에서는 릴리스 문장을 그대로 운영 판단으로 옮기기보다, 경고 로그 수집, 코드 소유권 분리, 라우트별 404 테스트, 프리뷰 배포 검증을 순서대로 진행해야 합니다. canary 릴리스의 가치는 빠른 적용보다 빠른 확인에 있습니다. 현재 프로젝트가 어떤 캐시 API에 의존하는지, 어떤 라우트에서 not-found.tsx가 표시되는지, 빌드와 런타임 로그가 어떻게 달라지는지 확인해 두면 이후 stable 업그레이드 비용을 줄일 수 있습니다.