
프로젝트 환경 구축하기
복잡한 셋팅을 일일히 만질 필요 없이 next-create-app CLI 도구 하나로, 환경을 구축합니다.
가장 먼저 체크할 것은 Node.js 버젼입니다.
Node.js 홈페이지에서 장기적인 안정성을 제공하는 Active LTS 버젼에 따르는지 확인해야 합니다.
실무 프로젝트에서는 반드시 이 버젼을 사용해야 합니다.
2026년 9월 기준으로 LTS는 다음과 같습니다.

Node.js 버전이 준비되었다면, 곧바로 프로젝트를 생성해보겠습니다.
우리는 복잡한 수동 설치 대신 Next.js 팀이 공식적으로 제공하고 유지보수하는 강력한 자동화 도구인
create-next-app을 사용할 것입니다. 터미널을 열고 다음과 같은 명령어를 입력하세요.
npx create-next-app@latest여기서 npx는 설치 없이 최신 패키지를 1회성으로 다운로드하여 실행하는 도구입니다.
@latest는 현재 시점 기준으로 가장 최신의 안정된 버젼을 보장합니다.
명령어 실행 후 이어지는 질문들이 프로젝트의 아키텍처의 뼈대가 됩니다.
1. 프로젝트 이름

프로젝트 이름을 영문으로 입력하되, 폴더 내에서 프로젝트를 생성하고 싶다면 ./를 입력해야 합니다.
2. 세부 설정

세부 설정을 하나하나 검토하고 결정하기 위해 3번인 No, customize settings를 선택합니다.
3. 타입스크립트 여부

Yes로 체크합니다. 타입 안정성은 타협할 수 없는 필수 요소이기 때문입니다.
4. 린터(Linter)

기본값인 ESLint를 선택합니다. 이는 코드의 문법적 오류나 스타일을 잡아주는 최소한의 안전 장치로써
협업과 유지보수를 위해 반드시 켜두어야 합니다.
5. React Compiler

Yes를 선택합니다. 이는 코드를 자동으로 최적화해주는 React의 신기술로
별도의 메모이제이션 없이도 성능을 극대화할 수 있기 때문입니다.
6. 테일윈드

Yes를 선택합니다. Next.js는 공식적으로 TailwindCSS를 기본 스타일링 엔진으로 사용합니다.
그리고, 가장 최적화된 설정을 자동으로 제공해줍니다.
7. 코드가 src 포함 여부

반드시 Yes를 선택하는 것을 적극 권장합니다. 프로젝트 루트에 설정 파일들이 쌓여가는 것을 방지하고
실제 소스 코드를 src 파일 안에 격리하여 관리하는 것이 실무의 표준 아키텍처이기 때문입니다.
8. 앱 라우터

반드시 Yes를 선택합니다. 만약 No로 선택 시 구 버젼인 페이지 라우터가 설치되므로 주의해야 합니다.
9. alias

No를 선택하여 복잡한 상대 경로 대신, @와 *를 사용한 깔끔한 상대 경로를 표현합니다.
이 모든 선택을 마치면, create-next-app은 우리가 선택한 옵션에 맞춰 최적의 보일러스테이트 코드를 생성합니다.
과거에는 Webpack, Typescript, Babel 설정 등 오랜 시간을 소비해야 했던 작업이 단 1분만에 끝나는 것입니다.
이제, Success 메시지가 떴다면, npm run dev를 이용하여 개발 서버를 실행합니다.

프로젝트 구조 해부하기
이 폴더 구조는 Next.js가 반드시 이렇게 개발해야 한다는 엄격한 법전이자 규칙입니다.
먼저, 프로젝트의 루트 폴더에 위치한 설정 파일부터 살펴봅니다.
이 파일들은 프로젝트의 뼈대와 규칙을 결정하는 중요한 문서들입니다.

1. 프로젝트의 설계 명세서 - package.json
프로젝트의 이름과 버전 뿐만 아니라, 어떤 외부 라이브러리에 의존하고 있는지 정확하게 기록되어 있으며
npm run dev와 같이 터미널에 입력하는 명령어들이 정의되어 있기도 합니다.
따라서 이 파일이 없으면 프로젝트는 구동조차 할 수 없습니다.
2. 엄격한 채점표 - tsconfig.json
타입스크립트라는 엄격한 감독관의 채점 기준표 역할을 합니다.
코드를 자바스크립트로 변환할 때 얼마나 엄격하게 검사할지 어떤 문법을 허용할지 결정하며
Next.js는 최적의 개발 경험을 위해 이 파일을 자동으로 설정해주는데 함부로 내용을 수정하면 안 됩니다.
3. 디자인 시스템 설정집 - tailwind.config.ts
우리가 사용할 색상 팔레트, 폰트 크기, 여백 등의 규칙이 정의되며
tailwindcss가 읽어서 우리가 필요한 스타일 등을 생성해냅니다.
4. 코드 경찰관 - .eslintrc.json
코드 규칙에 따르지 않을 경우 날리는 린터 설정 파일이며,
팀원들이 모두 같은 스타일의 코드를 짜도록 강제하는 중요한 파일입니다.
5. 중앙 관제탑 - next.config.ts
이미지 최적화 설정, 리다이렉트 규칙, 환경변수 설정 등 Next.js 서버가 동작하는 방식을 제어합니다.
6. 라이브러리를 모아둔 창고 - node_modules
package.json이 적힌 라이브러리들이 실제로 저장되는 거대한 창고입니다.
이 폴더는 절대 건드리면 안됩니다. 라이브러리 설치와 삭제는 오직 명령어로만 관리합니다.
이제 프로젝트의 핵심인 src/ 폴더로 접근해보겠습니다. 작성할 모든 소스 코드는 src/ 안에 격리됩니다.
그리고 src/ 안의 app 디렉토리가 Next.js App Router의 심장부입니다.
과거의 방식이나 다른 프레임워크에서는 라우팅을 위해 별도의 설정 파일을 코드에 작성해야 했으나
Next.js에서는 app 디렉토리 자체가 곧 Router입니다.
이 폴더 안에서 일어나는 파일 생성과 폴더 구조 변경이 곧바로, 브라우저의 URL 주소와 직결됩니다.
하지만 app 폴더 안에 파일을 아무렇게나 만든다고 해서 모두 화면에 나타나는 것은 아닙니다.
여기서 Next.js의 가장 중요한 철학인 파일 규칙이 등장합니다. 오직 약속된 이름을 가진 파일에게만 권한을 부여합니다.

이 파일은 단순한 작명 센스가 아니라 기능을 작동시키기 위한 키워드입니다.
가장 대표적이고 절대적인 파일이 page.tsx입니다. 이 파일은 해당 경로의 유일한 UI를 담당합니다.
만약 page.tsx라는 정확한 이름의 파일이 없다면 브라우저는 가차없이 404 에러를 띄웁니다.
그 다음으로 필수적인 파일이 layout.tsx입니다.
이 파일은 여러 페이지가 공유하는 공통의 껍데기 역할을 합니다.
app 폴더 안에 있는 layout.tsx는 html, body 태그를 포함하는데 이것을 Root Layout이라고 부릅니다.
이 파일은 애플리케이션의 모든 폴더의 파일을 감싸고 있으며, 우리가 어떤 페이지로 이동하든
절대 사라지거나 다시 생성되지 않고, 그대로 유지됩니다.
여기서는 children이라는 prop을 받고 있는데 바로 이 자리에 우리가 만든 page.tsx가 갈아끼워집니다.
이 방식은 Next.js가 레이아웃을 처리하는 고정된 처리 방식입니다.

이 외에도 loading.tsx, error.tsx, not-found.tsx 등 상황별로 보여줄 UI 파일 규칙을 제공합니다.
위치 병합(Location Colocation)
여기서 Next.js의 파일 시스템이 가진 강력한 철학인 **위치 병합(Colocation)**에 대해 알아보도록 합시다.
쉽게 말해 관련 코드는 멀리 두지 말고, 같이 두자는 원칙입니다.
과거 Next.js의 방식인 Page Router를 기반으로 살펴봅시다.
이 때는 파일을 생성하는 즉시 자동으로 주소가 되는 라우팅 방식이었습니다.
여기에는 치명적인 약점이 있는데, 다음과 같은 경우입니다.

개발자는 Chart.tsx 컴포넌트를 dashboard의 메인 컴포넌트의 서브 컴포넌트로 포함시키는 것이었지만,
Next.js에서는 이를 페이지로 오해하는 경우가 생깁니다. 이로 인해 의도치 않는 보안 사고가 발생합니다.
즉, 폴더 파일에 부품 파일로 만든 컴포넌트까지 덩달아 주소가 되어버리는 버그가 존재했습니다.
하지만, App Router에서는 dashboard 폴더가 하나의 방이며, 오직 page.tsx만 방으로 출입할 수 있습니다.
즉, page.tsx이라는 파일이 있어야만 주소를 만들고, 그 파일이 없으면 접근을 404 에러로 차단합니다.
따라서, 스타일 파일이나 내부 컴포넌트는 URL을 통해 외부에서 절대 접근할 수 없습니다.
예외적으로 루트 폴더의 public 폴더는 모든 정적 자원이 공개되는 오픈된 창고입니다.
앱 라우터 실습 - 중첩 레이아웃 구현
먼저 소개 페이지인 about 페이지를 만들어봅니다.
src/ 아래의 app/ 폴더에서 about/ 폴더를 새로 생성합니다.

그리고, 그 안에 page.tsx 파일을 생성합니다.

page.tsx에 다음과 같은 코드를 작성합니다.
export default function AboutPage() {
return (
<div className="p-10">
<h1 className="text-3xl font-bold">안녕하세요, About 페이지입니다.</h1>
<p className="mt-4 text-gray-600">
우리가 직접 만든 폴더가 곧바로 URL 주소가 되었습니다.
이것이 바로 파일 시스템 라우팅(File-System Routing)의 마법입니다.
</p>
</div>
)
}이 경로가 곧바로 URL인 /about이 됩니다. 여기서 page.tsx의 컴포넌트 이름은 어떻게 지어도 상관없습니다.
하지만 일부 섹션에는 그 섹션만의 공통 디자인이 필요하기 때문에, 여기서 layout.tsx의 능력이 발휘됩니다.

이 파일이 존재하는 순간, about 폴더와 그 하위의 모든 페이지는 layout.tsx 라는 껍데기 안에 갇히게 됩니다.
다음과 같은 코드를 살펴봅시다.
export default function AboutLayout({ children }: { children: React.ReactNode }) {
return (
<section className="border-4 border-blue-500 m-4 p-4 rounded-lg text-black">
<nav className="bg-blue-100 p-4 mb-4 rounded">
<h2 className="text-xl font-bold text-blue-800">
About 섹션 전용 네비게이션
</h2>
<ul className="flex gap-4 mt-2">
<li>소개</li>
<li>연혁</li>
<li>팀원</li>
</ul>
</nav>
<main className="bg-white">
{children}
</main>
</section>
)
}이 layout.tsx 파일은 그 폴더 페이지와 그 하위 페이지에만 적용되는 중첩 레이아웃입니다.
주목할 점은 레이아웃 컴포넌트는 반드시 children을 prop으로 받아야 한다는 것입니다.
추가로, layout.tsx는 중첩 레이아웃이라고 했는데, 이는 해당하는 폴더 및 그 하위에도 적용된다는 점입니다.

앱 라우터 실습 - 대시보드 사이드 바 구현
페이지가 바뀌어도 레이아웃은 절대 다시 그려지지 않는다는 것을 느낄 것입니다.
전통적인 HTML 방식은 페이지 이동 시 화면 전체가 깜빡이며 모든 상태가 초기화됩니다.
사이드바에 검색어를 입력하거나, 스크롤을 내려놨더라도, 모든 정보가 날아갔습니다.
그러나 Next.js의 레이아웃은 최초에 1번만 랜더링되고 그 자리에 고정됩니다.
가장 먼저, src/ 밑에 app/ 폴더 아래에 dashboard/ 디렉토리를 만듭니다.

그 안에 layout.tsx 파일을 생성합니다.

이후 다음과 같은 코드를 작성합니다.
import Link from "next/link";
import React from "react";
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex h-screen text-white">
<aside className="w-64 bg-gray-900 p-6 flex flex-col border-r border-gray-800">
<h1 className="text-2xl font-bold mb-6 text-emrald-400">Dev Dashboard</h1>
<div className="mb-6">
<input
type="text"
placeholder="검색어 입력"
className="w-full p-2 rounded bg-gray-800 text-sm focus:outline-none"
/>
<p className="text-xs text-gray-500 mt-2">여기에 글을 쓰고 메뉴를 이용해보세요!</p>
</div>
<nav className="space-y-2 flex-1 overflow-y-auto">
<Link
href="/dashboard"
className="block p-3 rounded hover:bg-gray-800 transition-colors"
>
Overview
</Link>
<Link
href="/dashboard/settings"
className="block p-3 rounded hover:bg-gray-800 transition-colors"
>
Settings
</Link>
</nav>
</aside>
<main className="flex-1 bg-gray-100 text-black p-8 overflow-y-auto">
{children}
</main>
</div>
)
}이제 UI 표현을 위해 page.tsx를 만듭니다.

그리고 다음과 같이 작성합니다.
export default function DashboardPage() {
return (
<div className="bg-white p-8 rounded-xl shadow-lg h-[2000px]">
<h2 className="text-3xl font-bold mb-4">환영합니다!</h2>
<p className="text-gray-600 mb-8">
이곳은 대시보드 메인 화면입니다. <br />
오른쪽 스크롤을 쭉 내려보세요. <br />
하지만 왼쪽 사이드바는 그 자리에 고정되어 있을 겁니다.
</p>
</div>
)
}이와 비슷하게 Settings 라우터를 구성하고, 사이드바에서 input 창에 Next.js라고 입력하고 페이지를 이동해봅시다.
확인하면, 아마 Next.js를 입력한 상태가 그대로 유지되는데 이것이 바로 상태 유지의 특성입니다.