콘텐츠로 이동

라우팅 완전 정복

Next.js의 라우팅은 파일 시스템 기반으로 동작합니다. 이 글에서는 App Router와 Page Router의 라우팅 시스템을 모두 다룹니다.

Page Router는 pages 폴더를 기반으로 합니다.

  • pages/index.tsx가 메인 페이지
  • 파일이 곧 하나의 페이지, 파일 이름이 경로
  • 폴더/index.tsxbaseUrl/폴더이름
  • 폴더/list.tsxbaseUrl/폴더이름/list
  • [id].tsx로 파일을 만들면 동적 경로 생성
  • useRouter()로 쿼리 파라미터 접근
import { useRouter } from "next/router";
function SomeComponent() {
const router = useRouter();
console.log(router.query); // { id: "something" }
console.log(router.pathname); // 현재 경로
}
  • [...slug].tsx로 파일 이름 설정
  • /폴더이름/id/2/guest{ slug: ["id", "2", "guest"] }
import Link from "next/link";
<Link
href={{
pathname: "clients/[id]",
query: { id: something },
}}
>
이동
</Link>

<a>와 같은 기능이지만 페이지 새로고침이 발생하지 않습니다.

  • (폴더명) 형태로 작성하면 URL 경로에 포함되지 않음
  • 각각의 layout.tsx 페이지를 생성 가능
  • 목적에 따라 파일 분류에도 활용
  • post/[id]post/1, post/2 가능, post/1/123 불가능
  • post/[[...id]] (Catch-All) → post/1/123, post/2/22/44 가능

별도의 경로를 가지는 2개의 페이지를 한 페이지에서 동시에 렌더링하는 것입니다. 폴더 경로는 @로 시작합니다.

- archive - layout.js
├── @archive - page.js
└── @latest - page.js
layout.js
export default function ArchiveLayout({ archive, latest }) {
return (
<div>
<section>{archive}</section>
<section>{latest}</section>
</div>
);
}

@ 뒤에 적힌 경로를 키로 가진 프로퍼티를 layout의 props에서 사용할 수 있습니다.

병렬 라우트에서의 중첩 라우트

섹션 제목: “병렬 라우트에서의 중첩 라우트”

default.js를 사용해야 합니다. archive 페이지에서 중첩 라우트인 /archive/someUrl로 이동하면 latest에서 보여줄 내용이 없어집니다. 이때 default.js를 통해 기본값을 설정합니다.

// @latest/default.js
export default function LatestDefault() {
return null;
}

인터셉팅 라우트 (Intercepting Routes)

섹션 제목: “인터셉팅 라우트 (Intercepting Routes)”
  • (.)intercept할URL : 같은 디렉토리
  • (..)intercept할URL : 상위 디렉토리
  • 새로고침이나 경로 직접 입력 시 해당 URL로 이동
  • Link 태그 등으로 접속 시 인터셉팅 페이지 실행

모달 구현: 인터셉트 + 병렬 라우팅

섹션 제목: “모달 구현: 인터셉트 + 병렬 라우팅”

서버 컴포넌트에서 모달을 구현할 때 사용합니다. 병렬 라우터는 폴더를 무시하므로 경로는 (.)으로 설정합니다.

@modal → (.)image ✅
@modal → (..)image ❌ (병렬 라우터가 폴더를 무시하므로)

Next.js 13 이후의 API 처리 방식입니다. HTTP 메서드별로 함수를 분리할 수 있습니다.

app/api/route.ts
export function GET(request) {
return new Response("Hello!");
}
export function POST(request) {
// POST 처리
}
  • api 폴더 내에 route.ts 생성 (같은 경로에 page.tsx가 있을 수 없음)
  • Next.js 애플리케이션을 모바일 앱의 API 서버로 활용할 때 유용

독립적인 비동기 작업은 병렬로 실행합니다:

// Anti-pattern: 순차 실행
export async function GET(request) {
const session = await auth();
const config = await fetchConfig();
const data = await fetchData(session.user.id);
return Response.json({ data, config });
}
// 올바른 패턴: 병렬 실행
export async function GET(request) {
const sessionPromise = auth();
const configPromise = fetchConfig();
const session = await sessionPromise;
const [config, data] = await Promise.all([
configPromise,
fetchData(session.user.id),
]);
return Response.json({ data, config });
}
  • "use client"에서만 사용 가능
  • router.back()으로 뒤로가기 실행
"use client";
import { useRouter } from "next/navigation";
function Component() {
const router = useRouter();
return <button onClick={() => router.back()}>뒤로가기</button>;
}

루트 경로에 middleware.ts를 생성하여 모든 요청을 검토할 수 있습니다. 인증 구현 시 자주 사용됩니다.

import { NextResponse } from "next/server";
export function middleware(request) {
// 인증 확인 등의 로직
return NextResponse.next();
}
// 특정 경로에만 적용
export const config = {
matcher: "/news",
};

빌드 타임에 한 번 실행되어 페이지를 사전 렌더링합니다.

export async function getStaticProps() {
return {
props: {
products: [{ id: "p1", title: "Product 1" }],
},
};
}
function Home(props) {
// props.products 사용
}

revalidate 프로퍼티를 추가하면 설정한 주기마다 페이지를 재생성합니다.

export async function getStaticProps() {
return {
props: { products: [{ id: "p1", title: "Product 1" }] },
revalidate: 10, // 10초마다 재생성
};
}

동적 라우트에서 사전 생성할 경로를 지정합니다.

export async function getStaticPaths() {
return {
paths: [
{ params: { productId: "p1" } },
{ params: { productId: "p2" } },
],
fallback: false,
};
}

fallback 옵션:

  • false: 지정하지 않은 경로는 404
  • true: 미생성 경로에 fallback 버전 제공
  • "blocking": HTML 생성까지 기다린 후 캐시

매 요청마다 서버에서 실행되어 새로운 데이터로 페이지를 생성합니다. getStaticPaths가 필요 없습니다.

export const getServerSideProps = (context) => {
const { params, req, res } = context;
return {
props: { userName: "Kim" },
};
};
기능Page RouterApp Router
기본 라우팅파일 기반폴더 기반
동적 라우팅[id].tsx[id]/page.tsx
APIpages/api/handler.tsapp/api/route.ts
사전 렌더링getStaticProps / getServerSideProps서버 컴포넌트

다음 글에서는 Next.js의 캐싱 전략을 살펴봅니다.