
🤓 1. 폴더 구조
Next.js는 React를 기반으로 한 프레임워크로, 파일 기반 라우팅, 서버 사이드 렌더링, 정적 사이트 생성 등 다양한 기능을 제공하며, 여기에 TypeScript(TSX)를 더하면 코드 안정성과 유지 보수성이 강화되어 대규모 프로젝트에 적합한 코드가 됩니다. 하지만 처음 시작할 때 어려운 부분이 바로 폴더구조이기에 이번 포스팅을 폴더 구조를 이해하는 방식에 대해 알아보겠습니다.
☺️ 2. 프로젝트 폴더 구조 이해
/app
/page.tsx ← index 페이지
/layout.tsx ← 공통 레이아웃
/components
Button.tsx
Header.tsx
/styles
globals.css
Button.module.css
/lib
fetcher.ts
/types
user.ts
/public
logo.png
/hooks
useAuth.ts
보통 next.js 프로젝트를 생성하면 이러한 방식으로 폴더를 구성합니다.
🚀 2-1. /app - 라우터 담당
- /app/page.tsx -> /
- /app/about/page.tsx -> /about
- layout.tsx를 통해 공통 레이아웃을 정의 가능
// app/layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>{children}</body>
</html>
);
}
- ☺️ App Router를 사용하면 서버 컴포넌트와 클라이언트 컴포넌트를 쉽게 구분 가능함
🚀 2-2. /components - UI 컴포넌트
재사용 가능한 UI 요소를 모아두는 폴더로 TypesScript를 사용하면 Props 타입을 지정 해 안전성을 높일 수 있습니다.
// components/Header.tsx
import React from "react";
interface HeaderProps {
title: string;
}
const Header: React.FC<HeaderProps> = ({ title }) => (
<header
style={{ padding: "20px", backgroundColor: "#0070f3", color: "#fff" }}
>
<h1>{title}</h1>
</header>
);
export default Header;
// components/Button.tsx
import React from "react";
import styles from "../styles/Button.module.css";
interface ButtonProps {
text: string;
onClick: () => void;
}
const Button: React.FC<ButtonProps> = ({ text, onClick }) => {
return (
<button className={styles.primary} onClick={onClick}>
{text}
</button>
);
};
export default Button;
/* styles/Button.module.css */
.primary {
background-color: #0070f3;
color: #fff;
padding: 10px 20px;
background-repeat: 6px;
cursor: pointer;
font-weight: bold;
}
- Button, Header 등 재사용 가능한 UI를 /components에 모아 유지보수에 용이하게 함
- Props 타입 지정으로 컴파일 단계에서 오류를 잡을 수 있음
🚀 2-3. /styles - CSS/SCSS 스타일
/* styles/global.css */
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
line-height: 1.6;
font-size: 18px;
background-color: #f9f9f9;
}
* {
box-sizing: border-box;
}
a {
color: #0070f3;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
img {
max-width: 100%;
display: block;
}
- 전역 스타일: global.css
- 컴포넌트별 스타일: Button.module.css
- CSS 모듈 사용으로 클래스명 충돌 방지
🚀 2-4. /lib - 유틸 함수 및 API 요청
공통 함수나 API 호출 코드를 관리하는 폴더입니다.
// lib/fetcher.ts
export async function fetcher<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error("Network error");
return res.json() as Promise<T>;
}
- TypeScript 제네릭을 활용하면 API 응답 타입 안정성 확보
- 반복되는 로직을 한 곳에 모아두면 재사용 가능
🚀 2-5. /types - 타입 정의
// types/user.ts
export interface User {
id: number;
name: string;
email: string;
}
- 모든 타입 정의를 /types에 모아두면 프로젝트 전체 일관성을 유지
- Props, API 응답 등 여러 곳에서 재사용
✅ 3. index 페이지 구성
이제 실제 index 페이지를 /app/page.tsx에 적용해보겠습니다.
// app/page.tsx
"use client";
import { useState } from "react";
import Header from "../components/Header";
import Button from "../components/Button";
export default function HomePage() {
const [count, setCount] = useState<number>(0);
const handleClick = () => setCount((prev) => prev + 1);
return (
<main style={{ padding: "40px", textAlign: "center" }}>
<Header title="TypeScript Blog" />
<p style={{ fontSize: "20px", margin: "20px 0" }}>
버튼 클릭 횟수: {count}
</p>
<Button text="클릭" onClick={handleClick} />
</main>
);
}
- 기능: 버튼 클랙 시 카운트 증가
- TypeScript 적용:
- useState<number>로 상태 타입 지정
- Button 컴포넌트 Props 타입 적용
✅ 4. 실행 및 확인
🚀 개발 서버 실행
npm run dev
🚀 브라우저에서 http://localhost:3000 열기
- 상단 Header 부분 확인 - TypeScript Blog
- 버튼 클릭 시 카운트 증가
- 글로벌 스타일 적용
GitHub - Koras02/nextjs-bloging: https://thinky.tistory.com/category/Front-End/NextJs
https://thinky.tistory.com/category/Front-End/NextJs - Koras02/nextjs-bloging
github.com
'Front-End > NextJs' 카테고리의 다른 글
| [Nextjs] 3장 React 기본기 (0) | 2025.08.18 |
|---|---|
| [Nextjs] 2장 Typescript 기본 문법 (1) | 2025.08.14 |
| [Nextjs] 1장 Next.js란? (1) | 2025.08.12 |