Next.js 01: Next.js 16 소개와 핵심 개념
Next.js의 탄생 배경과 철학, Next.js 16의 주요 변화, App Router의 장점, 프로젝트 구조를 이커머스 예제와 함께 학습합니다.
1. Next.js의 탄생 배경과 철학
2. Next.js 16의 주요 변화
3. App Router vs Pages Router
4. 프로젝트 구조 이해
5. 개발 환경 설정
6. 이커머스 예제: 첫 페이지 만들기
7. 정리 및 다음 단계
- • Next.js가 왜 필요한지, React만으로 부족한 점이 무엇인지 이해한다
- • Next.js 16의 새로운 기능과 React 19 통합을 파악한다
- • App Router의 장점과 Pages Router와의 차이를 이해한다
- • Next.js 프로젝트 구조를 파악하고 직접 프로젝트를 생성할 수 있다
1. Next.js의 탄생 배경과 철학
"React는 라이브러리입니다. 프레임워크가 아닙니다. 프로덕션 애플리케이션을 만들려면 더 많은 것이 필요합니다."
— Guillermo Rauch, Vercel CEO & Next.js 창시자
1.1 React만으로는 부족한 이유
React는 UI를 만들기 위한 훌륭한 라이브러리입니다. 하지만 "라이브러리"라는 점이 중요합니다. React만으로 실제 프로덕션 애플리케이션을 만들려면 수많은 결정을 직접 내려야 합니다.
React만 사용할 때 직접 결정해야 하는 것들
| 영역 | 직접 선택해야 하는 도구 | 고민 포인트 |
|---|---|---|
| 라우팅 | React Router, TanStack Router... | 어떤 라우터? 설정은? |
| 빌드 도구 | Vite, Webpack, Parcel... | 번들러 설정, 최적화 |
| 서버 렌더링 | 직접 구현 또는 포기 | SEO, 초기 로딩 속도 |
| 데이터 페칭 | fetch, axios, SWR, React Query... | 캐싱, 에러 처리 |
| 코드 스플리팅 | React.lazy, loadable-components... | 언제, 어떻게 분할? |
| API 라우트 | 별도 백엔드 서버 필요 | Express, Fastify... |
실제 겪는 문제
프로젝트를 시작할 때마다 "어떤 라우터를 쓸까?", "빌드 설정은 어떻게?", "SSR은 어떻게 구현하지?" 같은 고민에 시간을 쏟게 됩니다. 팀마다 다른 선택을 하면 프로젝트 간 일관성도 떨어집니다.
1.2 Next.js가 해결하는 문제
Next.js는 2016년 Vercel(당시 Zeit)에서 만들어졌습니다. "React 애플리케이션을 프로덕션에 배포하기 위해 필요한 모든 것"을 하나의 프레임워크로 제공하는 것이 목표였습니다.
✅ Next.js가 기본 제공하는 것
파일 기반 라우팅
폴더 구조 = URL 구조
서버 사이드 렌더링 (SSR)
SEO와 초기 로딩 최적화
정적 사이트 생성 (SSG)
빌드 시 HTML 생성
API 라우트
백엔드 없이 API 구현
자동 코드 스플리팅
페이지별 자동 분할
이미지 최적화
next/image 컴포넌트
폰트 최적화
next/font로 자동 최적화
TypeScript 지원
제로 설정 TypeScript
1.3 Next.js의 핵심 철학
🎯 Zero Config (제로 설정)
복잡한 Webpack 설정 없이 바로 시작할 수 있습니다. 필요하면 next.config.js로 확장 가능합니다.
# 이것만으로 프로젝트 시작! npx create-next-app@latest my-shop cd my-shop npm run dev
🎯 Convention over Configuration (설정보다 관례)
파일을 어디에 두느냐가 곧 설정입니다. app/products/page.tsx 파일을 만들면 /products 라우트가 자동 생성됩니다.
app/ ├── page.tsx → / ├── products/ │ ├── page.tsx → /products │ └── [id]/ │ └── page.tsx → /products/123
🎯 Hybrid Rendering (하이브리드 렌더링)
페이지마다 다른 렌더링 전략을 선택할 수 있습니다. 상품 목록은 SSG, 장바구니는 CSR, 주문 내역은 SSR처럼 최적의 방식을 조합합니다.
🎯 Full-Stack Framework (풀스택 프레임워크)
프론트엔드와 백엔드를 하나의 프로젝트에서 개발합니다. API 라우트와 Server Actions로 별도 백엔드 없이 데이터베이스 연동까지 가능합니다.
1.4 Next.js의 성장과 현재 위치
Next.js는 현재 가장 인기 있는 React 프레임워크입니다. 2026년 기준으로 Fortune 500 기업의 상당수가 Next.js를 사용하고 있습니다.
Next.js를 사용하는 대표 기업들
Netflix
스트리밍 서비스
TikTok
소셜 미디어
Notion
생산성 도구
Twitch
라이브 스트리밍
Hulu
스트리밍 서비스
Nike
이커머스
Target
리테일
Washington Post
미디어
왜 이커머스에 Next.js가 적합한가?
- • SEO: 상품 페이지가 검색 엔진에 잘 노출됨
- • 성능: 빠른 초기 로딩으로 이탈률 감소
- • 유연성: 정적/동적 페이지 혼합 가능
- • 확장성: 트래픽 증가에 대응 용이
2. Next.js 16의 주요 변화
Next.js 16은 2025년 말에 출시되어 2026년 현재 가장 최신 버전입니다. 이 버전은 React 19.2를 기본 탑재하고, 개발자 경험과 성능을 크게 개선했습니다.
Next.js 16 핵심 변화 요약
🚀 React 19.2 기본 탑재
⚡ React Compiler 정식 지원
🎬 View Transitions API
📦 Turbopack 정식 출시
🔄 개선된 캐싱 시스템
🎯 Partial Prerendering (PPR)
🛠️ 향상된 개발자 도구
📊 더 나은 에러 메시지
2.1 React 19.2와 React Compiler
Next.js 16은 React 19.2(canary)를 기본으로 사용합니다. 가장 큰 변화는 React Compiler가 정식으로 지원된다는 점입니다.
React Compiler란?
React Compiler(이전 이름: React Forget)는 컴포넌트를 자동으로 최적화합니다. 개발자가 useMemo, useCallback, React.memo를 직접 작성하지 않아도 컴파일러가 자동으로 메모이제이션을 적용합니다.
❌ 이전: 수동 최적화
function ProductCard({ product }) {
// 매번 새 객체 생성 → 리렌더링
const formattedPrice = useMemo(
() => formatPrice(product.price),
[product.price]
);
const handleClick = useCallback(
() => addToCart(product.id),
[product.id]
);
return (
<Card onClick={handleClick}>
<p>{formattedPrice}</p>
</Card>
);
}✅ 이제: 자동 최적화
// React Compiler가 자동 최적화!
function ProductCard({ product }) {
const formattedPrice = formatPrice(
product.price
);
const handleClick = () => {
addToCart(product.id);
};
return (
<Card onClick={handleClick}>
<p>{formattedPrice}</p>
</Card>
);
}React Compiler 활성화 방법
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
reactCompiler: true, // React Compiler 활성화
},
};
export default nextConfig;2.2 View Transitions API
페이지 전환 시 부드러운 애니메이션을 적용할 수 있는 View Transitions API가 React 19와 Next.js 16에서 지원됩니다.
View Transitions 예제
'use client';
import { useRouter } from 'next/navigation';
import { useTransition } from 'react';
export function ProductLink({ product }) {
const router = useRouter();
const [isPending, startTransition] = useTransition();
const handleClick = () => {
// View Transition으로 부드러운 페이지 전환
startTransition(() => {
router.push(`/products/${product.id}`);
});
};
return (
<div
onClick={handleClick}
style={{ viewTransitionName: `product-${product.id}` }}
className={isPending ? 'opacity-50' : ''}
>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
</div>
);
}viewTransitionName을 설정하면 해당 요소가 페이지 전환 시 자연스럽게 애니메이션됩니다. 상품 목록에서 상세 페이지로 이동할 때 이미지가 부드럽게 확대되는 효과를 줄 수 있습니다.
2.3 Turbopack 정식 출시
Rust로 작성된 새로운 번들러 Turbopack이 Next.js 16에서 정식으로 출시되었습니다. Webpack 대비 최대 10배 빠른 개발 서버 시작과 HMR(Hot Module Replacement)을 제공합니다.
Webpack vs Turbopack 성능 비교
| 항목 | Webpack | Turbopack | 개선 |
|---|---|---|---|
| 콜드 스타트 | ~3.5초 | ~0.5초 | 7x 빠름 |
| HMR (작은 변경) | ~500ms | ~50ms | 10x 빠름 |
| 대규모 앱 빌드 | ~60초 | ~15초 | 4x 빠름 |
Turbopack 사용 방법
# 개발 서버에서 Turbopack 사용 (Next.js 16 기본값) npm run dev # 명시적으로 Turbopack 사용 npm run dev -- --turbopack # 프로덕션 빌드 (아직 Webpack 사용) npm run build
Next.js 16에서는 개발 모드에서 Turbopack이 기본입니다. 프로덕션 빌드는 안정성을 위해 아직 Webpack을 사용합니다.
2.4 개선된 캐싱 시스템
Next.js 15에서 논란이 되었던 캐싱 동작이 Next.js 16에서 더 예측 가능하게 변경되었습니다.
캐싱 기본값 변경
| 항목 | Next.js 14 | Next.js 15 | Next.js 16 |
|---|---|---|---|
| fetch() 기본값 | 캐시됨 | 캐시 안됨 | 캐시 안됨 (명시적) |
| Route Handlers | 캐시됨 | 캐시 안됨 | 캐시 안됨 (명시적) |
| Client Router Cache | 5분 | 0초 | 설정 가능 |
Next.js 16에서는 캐싱을 원하면 명시적으로 설정해야 합니다. 이로 인해 "왜 데이터가 안 바뀌지?" 같은 혼란이 줄어들었습니다.
명시적 캐싱 설정 예제
// 캐시하지 않음 (기본값)
const products = await fetch('https://api.shop.com/products');
// 영구 캐시 (정적 데이터)
const categories = await fetch('https://api.shop.com/categories', {
cache: 'force-cache'
});
// 60초마다 재검증 (ISR)
const featuredProducts = await fetch('https://api.shop.com/featured', {
next: { revalidate: 60 }
});
// 태그 기반 캐시 무효화
const product = await fetch(`https://api.shop.com/products/${id}`, {
next: { tags: ['product', `product-${id}`] }
});2.5 Partial Prerendering (PPR)
PPR은 Next.js 16의 가장 혁신적인 기능입니다. 하나의 페이지에서 정적 부분과 동적 부분을 분리하여 렌더링합니다.
PPR 개념 이해
%%{init: {'theme': 'neutral'}}%%
flowchart TB
subgraph Page["상품 상세 페이지"]
subgraph Static["정적 (빌드 시 생성)"]
A["상품 이미지, 이름, 설명<br/>(변하지 않는 정보)"]
end
subgraph Dynamic1["동적 (요청 시 렌더링)"]
B["재고 현황: 12개 남음<br/>현재 가격: ₩29,900"]
end
subgraph Dynamic2["동적 (스트리밍)"]
C["추천 상품 (개인화)"]
end
end
Static --> Dynamic1 --> Dynamic2정적 부분은 CDN에서 즉시 제공되고, 동적 부분은 서버에서 스트리밍됩니다. 사용자는 정적 콘텐츠를 먼저 보고, 동적 콘텐츠가 로드되는 것을 기다립니다.
PPR 활성화 및 사용
// next.config.ts
const nextConfig = {
experimental: {
ppr: true, // PPR 활성화
},
};
// app/products/[id]/page.tsx
import { Suspense } from 'react';
// 정적 부분
async function ProductInfo({ id }) {
const product = await getProduct(id); // 빌드 시 실행
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
}
// 동적 부분
async function StockStatus({ id }) {
const stock = await getStock(id); // 요청 시 실행
return <p>재고: {stock.quantity}개</p>;
}
export default function ProductPage({ params }) {
return (
<div>
{/* 정적: 즉시 표시 */}
<ProductInfo id={params.id} />
{/* 동적: 스트리밍 */}
<Suspense fallback={<p>재고 확인 중...</p>}>
<StockStatus id={params.id} />
</Suspense>
</div>
);
}Next.js 16 업그레이드 체크리스트
- ✅ React 19 호환성 확인 (대부분 자동 호환)
- ✅ 캐싱 동작 변경 확인 (명시적 설정 필요)
- ✅ Turbopack 테스트 (개발 모드 기본)
- ✅ React Compiler 테스트 (선택적 활성화)
- ✅ PPR 검토 (점진적 도입 권장)
3. App Router vs Pages Router
Next.js에는 두 가지 라우팅 시스템이 있습니다. Next.js 13에서 도입된 App Router와 기존의 Pages Router입니다. 2026년 현재, 새 프로젝트는 App Router를 사용하는 것이 권장됩니다.
두 라우터의 핵심 차이
| 특성 | Pages Router | App Router |
|---|---|---|
| 디렉토리 | pages/ | app/ |
| 기본 컴포넌트 | Client Components | Server Components |
| 데이터 페칭 | getServerSideProps, getStaticProps | async/await in Components |
| 레이아웃 | _app.tsx, _document.tsx | layout.tsx (중첩 가능) |
| 로딩 UI | 직접 구현 | loading.tsx (자동) |
| 에러 처리 | _error.tsx | error.tsx (세분화) |
| 스트리밍 | 제한적 | Suspense 기반 완전 지원 |
3.1 파일 구조 비교
Pages Router (pages/)
pages/
├── _app.tsx # 전역 레이아웃
├── _document.tsx # HTML 문서
├── index.tsx # /
├── about.tsx # /about
├── products/
│ ├── index.tsx # /products
│ └── [id].tsx # /products/123
└── api/
└── products.ts # API 라우트App Router (app/)
app/
├── layout.tsx # 루트 레이아웃
├── page.tsx # /
├── about/
│ └── page.tsx # /about
├── products/
│ ├── page.tsx # /products
│ ├── layout.tsx # 상품 레이아웃
│ ├── loading.tsx # 로딩 UI
│ └── [id]/
│ └── page.tsx # /products/123
└── api/
└── products/
└── route.ts # API 라우트3.2 데이터 페칭 비교
가장 큰 차이는 데이터를 가져오는 방식입니다. Pages Router는 특별한 함수를 사용하고, App Router는 컴포넌트에서 직접 async/await를 사용합니다.
Pages Router 방식
// pages/products/[id].tsx
// 1. 데이터 페칭 함수 (별도)
export async function getServerSideProps(
context
) {
const { id } = context.params;
const res = await fetch(
`https://api.shop.com/products/${id}`
);
const product = await res.json();
return {
props: { product }
};
}
// 2. 컴포넌트 (props로 받음)
export default function ProductPage({
product
}) {
return (
<div>
<h1>{product.name}</h1>
<p>{product.price}</p>
</div>
);
}App Router 방식
// app/products/[id]/page.tsx
// 컴포넌트에서 직접 데이터 페칭!
export default async function ProductPage({
params
}) {
const { id } = await params;
// 서버 컴포넌트에서 직접 fetch
const res = await fetch(
`https://api.shop.com/products/${id}`
);
const product = await res.json();
return (
<div>
<h1>{product.name}</h1>
<p>{product.price}</p>
</div>
);
}App Router의 장점
- • 직관적: 컴포넌트에서 바로 데이터 페칭
- • 간결함: getServerSideProps 같은 보일러플레이트 제거
- • 유연함: 컴포넌트 단위로 렌더링 전략 선택
- • 성능: Server Components로 번들 크기 감소
3.3 레이아웃 시스템 비교
Pages Router: _app.tsx
// pages/_app.tsx
// 모든 페이지에 적용되는 단일 레이아웃
export default function App({
Component,
pageProps
}) {
return (
<Layout>
<Header />
<Component {...pageProps} />
<Footer />
</Layout>
);
}
// 문제: 페이지별 다른 레이아웃 적용이 복잡App Router: 중첩 레이아웃
// app/layout.tsx (루트)
export default function RootLayout({ children }) {
return (
<html>
<body>
<Header />
{children}
<Footer />
</body>
</html>
);
}
// app/products/layout.tsx (상품 전용)
export default function ProductsLayout({ children }) {
return (
<div className="products-container">
<Sidebar />
{children}
</div>
);
}
// 장점: 레이아웃이 자동으로 중첩됨!3.4 왜 App Router를 선택해야 하는가?
1. Server Components = 더 작은 번들
서버에서만 실행되는 컴포넌트는 클라이언트로 JavaScript를 보내지 않습니다. 이커머스에서 상품 목록을 Server Component로 만들면 수십 KB의 JavaScript를 절약할 수 있습니다.
2. Streaming = 더 빠른 TTFB
페이지의 일부를 먼저 보내고 나머지를 스트리밍합니다. 사용자는 전체 페이지가 준비될 때까지 기다리지 않아도 됩니다.
3. 세분화된 로딩/에러 처리
loading.tsx, error.tsx를 폴더별로 배치하여 각 섹션에 맞는 로딩 UI와 에러 처리를 제공합니다.
4. 미래 지향적
React의 새로운 기능(Server Components, Suspense, Transitions)은 App Router에서만 완전히 지원됩니다. Pages Router는 유지보수 모드입니다.
Pages Router를 사용해야 하는 경우
- • 기존 Pages Router 프로젝트를 유지보수하는 경우
- • App Router를 지원하지 않는 라이브러리를 사용하는 경우
- • 팀이 아직 Server Components에 익숙하지 않은 경우
하지만 새 프로젝트라면 App Router로 시작하는 것을 강력히 권장합니다.
3.5 이커머스에서의 App Router 활용
이커머스 라우트 구조 예시
app/
├── layout.tsx # 공통 헤더/푸터
├── page.tsx # 홈페이지
│
├── (home)/ # Route Group: 홈 관련
│ ├── layout.tsx # 홈 전용 레이아웃
│ └── page.tsx
│
├── (shop)/ # Route Group: 쇼핑 관련
│ ├── layout.tsx # 사이드바 포함 레이아웃
│ ├── products/
│ │ ├── page.tsx # 상품 목록 (SSG + ISR)
│ │ ├── loading.tsx # 상품 로딩 스켈레톤
│ │ └── [id]/
│ │ ├── page.tsx # 상품 상세 (PPR)
│ │ └── loading.tsx
│ └── categories/
│ └── [slug]/
│ └── page.tsx # 카테고리별 상품
│
├── (purchase-flow)/ # Route Group: 구매 플로우
│ ├── layout.tsx # 단순화된 레이아웃 (헤더만)
│ ├── cart/
│ │ └── page.tsx # 장바구니 (CSR)
│ ├── checkout/
│ │ └── page.tsx # 결제 (SSR)
│ └── order/
│ └── [id]/
│ └── page.tsx # 주문 완료
│
└── api/ # API Routes
├── products/
│ └── route.ts
└── cart/
└── route.tsRoute Group의 활용
(home), (shop), (purchase-flow)처럼 괄호로 감싼 폴더는 URL에 영향을 주지 않으면서 레이아웃을 분리합니다. 홈페이지는 풀 화면, 상품 페이지는 사이드바 포함, 결제 페이지는 단순화된 레이아웃을 각각 적용할 수 있습니다.
4. 프로젝트 구조 이해
Next.js 프로젝트의 디렉토리 구조를 이해하면 어디에 무엇을 두어야 하는지 명확해집니다. 각 폴더와 파일의 역할을 알아봅시다.
4.1 기본 프로젝트 구조
create-next-app으로 생성된 구조
my-shop/ ├── app/ # 🎯 App Router (핵심!) │ ├── layout.tsx # 루트 레이아웃 │ ├── page.tsx # 홈페이지 (/) │ ├── globals.css # 전역 스타일 │ └── favicon.ico # 파비콘 │ ├── public/ # 📁 정적 파일 │ ├── images/ # 이미지 파일 │ └── fonts/ # 폰트 파일 │ ├── components/ # 🧩 재사용 컴포넌트 (선택) │ ├── ui/ # UI 컴포넌트 │ └── ... │ ├── lib/ # 📚 유틸리티 함수 (선택) │ └── utils.ts │ ├── next.config.ts # ⚙️ Next.js 설정 ├── package.json # 📦 의존성 ├── tsconfig.json # 🔷 TypeScript 설정 ├── tailwind.config.ts # 🎨 Tailwind 설정 (선택) └── postcss.config.mjs # CSS 후처리 설정
4.2 app/ 디렉토리 상세
app/ 디렉토리는 App Router의 핵심입니다. 여기에 있는 파일들은 특별한 의미를 가집니다.
app/ 내 특수 파일들
| 파일명 | 역할 | 설명 |
|---|---|---|
| page.tsx | 페이지 UI | 해당 라우트의 메인 컴포넌트 |
| layout.tsx | 레이아웃 | 하위 페이지를 감싸는 공통 UI |
| loading.tsx | 로딩 UI | 페이지 로딩 중 표시 |
| error.tsx | 에러 UI | 에러 발생 시 표시 |
| not-found.tsx | 404 UI | 페이지를 찾을 수 없을 때 |
| route.ts | API 라우트 | 서버 API 엔드포인트 |
| template.tsx | 템플릿 | 매번 새로 마운트되는 레이아웃 |
| default.tsx | 기본 UI | Parallel Routes 기본값 |
각 파일의 실제 예시
// 루트 레이아웃 - 모든 페이지에 적용
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata = {
title: 'My Shop',
description: '최고의 쇼핑몰',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body className={inter.className}>
<header>헤더</header>
<main>{children}</main>
<footer>푸터</footer>
</body>
</html>
);
}// 상품 목록 로딩 중 표시되는 스켈레톤 UI
export default function ProductsLoading() {
return (
<div className="grid grid-cols-4 gap-4">
{[...Array(8)].map((_, i) => (
<div key={i} className="animate-pulse">
<div className="bg-gray-200 h-48 rounded-lg" />
<div className="bg-gray-200 h-4 mt-2 rounded" />
<div className="bg-gray-200 h-4 mt-1 w-1/2 rounded" />
</div>
))}
</div>
);
}'use client'; // 에러 컴포넌트는 Client Component여야 함
export default function ProductsError({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div className="text-center py-10">
<h2>상품을 불러오는데 실패했습니다</h2>
<p className="text-muted-foreground">{error.message}</p>
<button onClick={reset} className="mt-4 btn">
다시 시도
</button>
</div>
);
}4.3 라우팅 규칙
폴더 구조 → URL 매핑
| 폴더 구조 | URL | 설명 |
|---|---|---|
| app/page.tsx | / | 홈페이지 |
| app/about/page.tsx | /about | 정적 라우트 |
| app/products/[id]/page.tsx | /products/123 | 동적 라우트 |
| app/blog/[...slug]/page.tsx | /blog/a/b/c | Catch-all |
| app/(shop)/products/page.tsx | /products | Route Group (URL 무영향) |
| app/api/products/route.ts | /api/products | API 엔드포인트 |
4.4 public/ 디렉토리
public/ 폴더의 파일은 루트 URL에서 직접 접근할 수 있습니다.
public/ ├── images/ │ ├── logo.png → /images/logo.png │ └── products/ │ └── item1.jpg → /images/products/item1.jpg ├── fonts/ │ └── custom.woff2 → /fonts/custom.woff2 ├── favicon.ico → /favicon.ico └── robots.txt → /robots.txt
주의: public/ 폴더의 파일은 빌드 시 최적화되지 않습니다. 이미지는 가능하면 next/image를 사용하세요.
4.5 설정 파일들
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
// 이미지 최적화 설정
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.myshop.com',
},
],
},
// 실험적 기능
experimental: {
reactCompiler: true, // React Compiler
ppr: true, // Partial Prerendering
},
// 리다이렉트
async redirects() {
return [
{
source: '/old-products',
destination: '/products',
permanent: true,
},
];
},
};
export default nextConfig;{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"strict": true,
"module": "esnext",
"moduleResolution": "bundler",
"jsx": "preserve",
// 경로 별칭 설정 (중요!)
"baseUrl": ".",
"paths": {
"@/*": ["./*"],
"@/components/*": ["./components/*"],
"@/lib/*": ["./lib/*"]
}
}
}경로 별칭 활용하기
tsconfig.json의 paths 설정으로 깔끔한 import가 가능합니다.
// ❌ 상대 경로 (복잡)
import { Button } from '../../../components/ui/button';
// ✅ 경로 별칭 (깔끔)
import { Button } from '@/components/ui/button';4.6 권장 프로젝트 구조 (이커머스)
실무에서 사용하는 확장된 구조
my-ecommerce/ ├── app/ # 라우팅 & 페이지 │ ├── (home)/ │ ├── (shop)/ │ │ ├── products/ │ │ └── categories/ │ ├── (purchase-flow)/ │ │ ├── cart/ │ │ ├── checkout/ │ │ └── order/ │ ├── api/ │ ├── layout.tsx │ └── globals.css │ ├── components/ # 재사용 컴포넌트 │ ├── ui/ # 기본 UI (Button, Card...) │ ├── forms/ # 폼 컴포넌트 │ └── layouts/ # 레이아웃 컴포넌트 │ ├── lib/ # 유틸리티 │ ├── api/ # API 클라이언트 │ ├── hooks/ # 커스텀 훅 │ ├── utils/ # 헬퍼 함수 │ └── validations/ # Zod 스키마 │ ├── types/ # TypeScript 타입 │ ├── product.ts │ ├── cart.ts │ └── order.ts │ ├── stores/ # 상태 관리 (Zustand) │ ├── cart-store.ts │ └── user-store.ts │ ├── public/ # 정적 파일 │ └── images/ │ └── 설정 파일들...
5. 개발 환경 설정
Next.js 프로젝트를 시작하기 위한 개발 환경을 설정합니다.
5.1 사전 요구사항
Node.js 18.17 이상
권장: Node.js 20 LTS
패키지 매니저
npm, pnpm, yarn, bun 중 선택
VS Code
권장 에디터
5.2 프로젝트 생성
create-next-app 실행
npx create-next-app@latest my-shop # 설치 옵션 ✔ Would you like to use TypeScript? … Yes ✔ Would you like to use ESLint? … Yes ✔ Would you like to use Tailwind CSS? … Yes ✔ Would you like your code inside a 'src/' directory? … No ✔ Would you like to use App Router? (recommended) … Yes ✔ Would you like to use Turbopack for 'next dev'? … Yes
5.3 VS Code 확장
ES7+ React Snippets
Tailwind CSS IntelliSense
ESLint
Prettier
5.4 Prettier 설정
npm install -D prettier prettier-plugin-tailwindcss
.prettierrc
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"plugins": ["prettier-plugin-tailwindcss"]
}5.5 개발 서버 실행
cd my-shop npm run dev # http://localhost:3000 에서 확인
체크리스트
- ✅ Node.js 18.17+ 설치
- ✅ create-next-app으로 프로젝트 생성
- ✅ VS Code 확장 설치
- ✅ npm run dev 실행 확인
6. 이커머스 예제: 첫 페이지 만들기
실제 이커머스 홈페이지의 기본 구조를 만들어봅니다.
6.1 레이아웃 구성
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
export const metadata: Metadata = {
title: 'MyShop - 온라인 쇼핑몰',
description: '다양한 상품을 만나보세요',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body className={inter.className}>
<header className="border-b">
<div className="container mx-auto flex h-16 items-center px-4">
<a href="/" className="text-xl font-bold">MyShop</a>
<nav className="ml-auto flex gap-4">
<a href="/products">상품</a>
<a href="/cart">장바구니</a>
</nav>
</div>
</header>
<main className="container mx-auto px-4 py-8">
{children}
</main>
<footer className="border-t py-6 text-center text-sm">
© 2026 MyShop
</footer>
</body>
</html>
);
}6.2 상품 타입 정의
export interface Product {
id: string;
name: string;
price: number;
image: string;
category: string;
}6.3 홈페이지
// Server Component (기본값)
async function getProducts() {
// 실제로는 API 호출
return [
{ id: '1', name: '스마트폰', price: 990000, image: '/phone.jpg', category: '전자기기' },
{ id: '2', name: '노트북', price: 1500000, image: '/laptop.jpg', category: '전자기기' },
];
}
export default async function HomePage() {
const products = await getProducts();
return (
<div>
<h1 className="text-3xl font-bold mb-8">인기 상품</h1>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{products.map((product) => (
<a
key={product.id}
href={`/products/${product.id}`}
className="border rounded-lg p-4 hover:shadow-lg"
>
<img
src={product.image}
alt={product.name}
className="w-full aspect-square object-cover rounded"
/>
<h2 className="mt-2 font-medium">{product.name}</h2>
<p className="text-lg font-bold">
{product.price.toLocaleString()}원
</p>
</a>
))}
</div>
</div>
);
}핵심 포인트
- • page.tsx는 기본적으로 Server Component
- • async/await로 서버에서 데이터 페칭
- • 클라이언트에 JavaScript 번들 전송 없음
7. 정리 및 다음 단계
학습 내용 요약
Next.js의 탄생 배경
React의 한계를 극복하기 위한 풀스택 프레임워크
Next.js 16의 주요 변화
React 19, Turbopack, PPR 등 최신 기능
App Router
파일 기반 라우팅과 레이아웃 시스템
프로젝트 구조
app 디렉토리와 특수 파일들의 역할
다음 강의 예고
2강: Server Components와 Client Components
- • Server Components의 혁명적 변화
- • Client Components와 'use client' 지시어
- • 컴포넌트 구성 패턴과 경계 설계
- • 이커머스 예제: 상품 상세 페이지
실습 과제
- 1
create-next-app으로 새 프로젝트 생성하기
- 2
app/page.tsx 수정하여 자신만의 홈페이지 만들기
- 3
app/about/page.tsx 추가하여 라우팅 확인하기