출시·고도화 중
Next.js 안내서 · 2/6
Next.js는 폴더와 파일 이름으로 주소와 화면 구성을 정하는 파일 시스템 기반 라우팅을 씁니다. 그래서 어떤 파일을 어디에 두는지가 곧 애플리케이션의 구조가 됩니다. 이 장에서는 기본 폴더와 설정 파일, 특별한 이름을 가진 파일, 그리고 자주 쓰는 정리 규칙을 살펴봅니다.
create-next-app으로 만든 프로젝트는 대략 다음과 같이 생겼습니다(선택한 옵션에 따라 조금 다릅니다).
my-app/
app/
layout.tsx 루트 레이아웃
page.tsx 첫 화면 /
globals.css 전역 스타일
favicon.ico
public/ 이미지 등 정적 파일
next.config.ts Next.js 설정
tsconfig.json TypeScript 설정
eslint.config.mjs 린트 설정
package.json
next-env.d.ts 자동 생성되는 타입 선언| 폴더 · 파일 | 역할 |
|---|---|
app | 라우트, 레이아웃, 페이지가 들어가는 App Router 폴더 |
public | 그대로 제공되는 정적 파일. public/logo.png는 /logo.png로 열립니다 |
src | 선택 사항. 고르면 app을 src/app에 둡니다 |
next.config.ts | 이미지 도메인, 리디렉션, 출력 방식 같은 프레임워크 설정 |
.env* | 환경 변수 파일 |
proxy.ts | 요청이 처리되기 전에 실행하는 코드. 이전 버전에서는 middleware.ts라는 이름이었습니다 |
app 폴더 안에서는 정해진 이름의 파일만 특별한 뜻을 가집니다. 한 폴더(라우트 세그먼트) 안에 다음 파일을 둘 수 있습니다.
| 파일 | 뜻 |
|---|---|
page.tsx | 그 주소의 화면. 이 파일이 있어야 주소가 공개됩니다 |
layout.tsx | 하위 페이지를 감싸는 틀. 페이지를 이동해도 상태가 유지됩니다 |
loading.tsx | 내용을 불러오는 동안 보여 줄 화면(Suspense 대체 화면) |
error.tsx | 하위에서 오류가 났을 때 보여 줄 화면(Client Component) |
not-found.tsx | notFound()를 호출했거나 없는 주소일 때의 화면 |
route.ts | 화면 대신 HTTP 응답을 돌려주는 Route Handler |
template.tsx | 레이아웃과 비슷하지만 이동할 때마다 새로 만들어집니다 |
이 규칙 덕분에 컴포넌트, 스타일, 테스트 파일을 라우트 폴더 안에 함께 두어도(colocation) 괜찮습니다. page.tsx나 route.ts가 아닌 파일은 주소로 공개되지 않기 때문입니다.
폴더 이름에 대괄호를 쓰면 주소의 일부를 매개변수로 받습니다. 최근 버전에서는 params가 Promise로 전달되므로 await로 꺼내 씁니다.
// app/blog/[slug]/page.tsx → /blog/hello-world
export default async function PostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
return <h1>글: {slug}</h1>;
}폴더 이름에 쓰는 규칙은 다음과 같습니다.
[slug]: 한 단계 동적 세그먼트[...slug]: 여러 단계를 모두 받는 세그먼트(/docs/a/b/c)[[...slug]]: 매개변수가 없는 주소까지 받는 선택적 세그먼트(marketing): 괄호로 묶은 라우트 그룹. 주소에는 나타나지 않고, 레이아웃을 나누거나 파일을 정리할 때 씁니다_components: 밑줄로 시작하는 비공개 폴더. 라우팅에서 완전히 빠집니다프레임워크 설정은 프로젝트 루트의 next.config.ts(또는 .js, .mjs)에 씁니다. TypeScript로 쓰면 설정 항목을 자동 완성으로 확인할 수 있습니다.
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
images: {
remotePatterns: [{ protocol: "https", hostname: "images.example.com" }],
},
async redirects() {
return [{ source: "/old-blog/:slug", destination: "/blog/:slug", permanent: true }];
},
};
export default nextConfig;tsconfig.json의 paths 설정으로 @/를 프로젝트 루트(또는 src)에 연결해 두면, 깊은 상대 경로 대신 import { db } from "@/lib/db"처럼 쓸 수 있습니다. create-next-app은 이 별칭을 기본으로 설정합니다.
환경 변수는 .env, .env.local, .env.development, .env.production 같은 파일에서 읽습니다. 비밀 값은 저장소에 올리지 않는 .env.local에 두는 것이 일반적입니다.
# .env.local
DATABASE_URL=postgres://user:pass@localhost:5432/app
NEXT_PUBLIC_SITE_NAME=My App이름이 NEXT_PUBLIC_으로 시작하는 변수만 브라우저 코드에 포함됩니다. 그 밖의 변수는 서버에서만 읽을 수 있으므로, 데이터베이스 주소나 API 키 같은 비밀 값에는 이 접두사를 붙이지 않습니다.
app 폴더에는 검색 엔진과 공유용 파일도 규칙에 따라 둘 수 있습니다. favicon.ico, icon.png, opengraph-image.png를 두면 해당 태그가 자동으로 만들어지고, robots.ts와 sitemap.ts는 코드로 내용을 생성합니다.
// app/sitemap.ts
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: "https://example.com", lastModified: new Date() },
{ url: "https://example.com/about", lastModified: new Date() },
];
}app 폴더 구조로 정해지고, page.tsx나 route.ts가 있어야 공개됩니다.layout, loading, error, not-found 같은 특별한 파일이 화면 구성을 나눠 맡습니다.[slug], (group), _private 같은 폴더 이름 규칙으로 동적 주소와 정리를 함께 해결합니다.next.config.ts, 비밀 값은 .env.local에 두며, 브라우저에 보낼 값만 NEXT_PUBLIC_을 붙입니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.