Community코딩 & 개발github.com

Next.js 프로덕션 스택

Next.js (App Router) 애플리케이션 구축, 스캐폴딩, 확장, 리뷰 및 디버깅을 위한 권장 풀스택 규칙입니다. TypeScript, Tailwind + shadcn/ui, React Hook Form + Zod, PostgreSQL + Drizzle, Better Auth, SEO, 접근성, 테스트, 모니터링 등 프로덕션 스택 전반을 다룹니다.

Next.js 프로덕션 스택란 무엇인가요?

이 스킬은 Next.js 애플리케이션(특히 App Router 사용)을 개발할 때 따라야 할 포괄적이고 의견이 반영된 규칙들을 제공합니다. 프로젝트 스캐폴딩, TypeScript 및 코드 품질 설정, 렌더링 전략(정적/동적), 데이터베이스 스키마(Drizzle ORM 사용), 인증(Better Auth), 폼 검증(React Hook Form + Zod), UI 컴포넌트(Tailwind + shadcn/ui), SEO, 접근성, 테스트(Vitest, Playwright), 모니터링(Sentry), DevOps(GitHub Actions, Vercel) 등 프로덕션 준비에 필요한 모든 측면을 다룹니다.[Redoy49/nextjs-production-stack](https://github.com/redoy49/nextjs-production-stack) 또는 유사한 스택을 사용하는 프로젝트에 적용하도록 설계되었습니다. 이 스킬은 Claude Code, Cursor 등의 AI 코딩 도우미가 프로젝트 내에서 일관된 코딩 패턴을 유지하고, 실수를 방지하며, 확장 가능하고 유지보수 가능한 코드를 생성하도록 돕습니다. 이 스킬의 핵심은 '권장(엄격하지 않음)' 규칙으로, 도구 변경 전 사용자와 상의하고 기존 프로젝트 패턴을 존중하며 명시적인 허가 없이 스택을 대체하지 않도록 합니다.

지원 대상✓Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/redoy49/agent-skills/tree/main/skills/web/nextjs-production-stack

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Next.js 프로덕션 스택은(는) 무엇을 하나요?

Next.js 애플리케이션을 구축하고 유지보수하기 위한 의견이 반영된 기본 규칙입니다. 새 프로젝트를 스캐폴딩하거나 기존 프로젝트에 기능을 추가할 때는 아래 규칙을 따르십시오. 단, 사용자의 기존 코드베이스가 명백히 다른 방식을 사용하는 경우 해당 패턴을 우선시하고 이 문서와의 차이점을 간략히 기록해 두십시오.

0. 스택 개요

계층권장 (엄격하지 않음)변경 요청 시 제안할 대안
프레임워크Next.js (App Router), TypeScript, 서버 컴포넌트 + 서버 액션필요 없음, 이것이 핵심입니다
패키지 매니저pnpmnpm, yarn, bun
UITailwind CSS, shadcn/ui, react-icons, Motion (motion.dev)Radix UI 또는 Mantine, lucide-react, CSS Modules
폼React Hook Form + ZodTanStack Form, Zod 대신 Valibot
데이터베이스PostgreSQL + Drizzle ORMPrisma, Kysely; 소규모 앱의 경우 MySQL 또는 SQLite
인증Better Auth, RBACAuth.js, Clerk, Supabase Auth
미디어CloudinaryUploadThing, S3 + CDN, Vercel Blob
테스트Vitest (단위/통합), Playwright (E2E)Jest, Cypress
모니터링Sentry, 구조화된 로깅Datadog, Highlight, Axiom + pino
린트/포맷ESLint, Prettier, TypeScript strictBiome
CI/CDGitHub + GitHub Actions, Vercel, 프리뷰 배포GitLab CI, Netlify, Cloudflare Pages

이 표의 패키지를 대안(예: Drizzle 대신 Prisma, Better Auth 대신 next-auth)으로 절대 조용히 교체하지 마십시오. 사용자의 프로젝트가 이미 다른 선택지를 사용하고 있다면, 그 선택지를 계속 사용하고 차이점을 표시하십시오. 동일한 작업을 위해 두 가지 솔루션을 혼용하지 마십시오.

이 도구들은 권장됩니다: 사용자가 선호하지만 엄격하지는 않습니다.

  • 이후 섹션에서 특정 도구(pnpm, Drizzle, Better Auth, Cloudinary, Sentry 등)를 언급하는 경우, 이 규칙에 따른 권장 기본값으로 읽어야 합니다.
  • 표의 도구를 변경, 교체 또는 건너뛰기 전에 사용자에게 먼저 물어보십시오. 권장 도구를 유지하거나, 마지막 열(또는 다른 모범 사례)의 대안 중에서 선택지를 제시하고, 각각의 장단점을 한 줄로 설명하고 귀하의 추천을 함께 제시하십시오.
  • 대안을 추천하기 전에 현재 상태(유지보수 상태, 주요 변경 사항)를 확인하십시오. 메모리에만 의존하지 마십시오.
  • 답변 없이 도구를 변경하지 마십시오. 사용자가 답변할 때까지 권장 기본값을 유지하십시오.

1. 프로젝트 설정

  • pnpm create next-app@latest로 스캐폴딩합니다. TypeScript, App Router, Tailwind, ESLint를 모두 활성화하고, src/ 디렉토리는 거절하여 app/이 프로젝트 루트에 위치하도록 합니다(새 프로젝트만 해당).
  • 이미 src/를 사용하는 기존 프로젝트: src/를 유지합니다. 즉, src/app/, src/components/, src/lib/, src/actions/를 사용합니다. app/은 프로젝트에 src/ 디렉토리가 없을 때만 사용합니다. 기존 레이아웃과 가져오기 별칭(@/* → src/*)을 따르십시오. 관련 없는 작업의 일환으로 src/ 밖으로 파일을 절대 이동하지 마십시오.
  • 모든 설치/실행 명령어(pnpm add, pnpm dlx, pnpm dev)에 pnpm을 사용하십시오. npm/yarn 잠금 파일을 절대 혼용하지 마십시오.
  • pnpm dlx shadcn@latest init로 shadcn/ui를 초기화한 다음, 전체 세트를 미리 설치하지 말고 필요에 따라 컴포넌트를 추가하십시오(pnpm dlx shadcn@latest add button).
  • 기본 폴더 구조 (src/ 없음 — app/이 프로젝트 루트):
# 새 프로젝트 (src/ 없음)
app/                   # 라우트, 레이아웃, error/loading/not-found 경계
components/            # 공유 UI (ui/ = shadcn 프리미티브)
lib/                   # db, auth, 검증, 유틸리티, rate-limit, 로거
actions/               # 도메인별로 그룹화된 서버 액션
hooks/
types/
drizzle/               # 마이그레이션

기존 src/ 프로젝트: src/ 아래 동일한 구조(src/app/, src/components/, src/lib/, src/actions/) — 폴더 이름은 동일하게 유지되고 접두사만 변경됩니다.

2. TypeScript 및 코드 품질

  • tsconfig에서 strict: true, 사유를 주석으로 명시하지 않은 any는 제외, 연결된 이슈/사유 없는 @ts-ignore는 제외.
  • 코드가 완료된 것으로 간주되기 전에 ESLint(next/core-web-vitals + typescript-eslint)와 Prettier를 구성하고 통과해야 합니다. 실행하십시오. 단순히 가정하지 마십시오.
  • 내보낸 함수와 서버 액션에는 명시적 반환 유형을 선호합니다.
  • 서버 컴포넌트를 기본값으로 유지하십시오. 상호작용성, 브라우저 API 또는 훅이 필요한 경우에만 "use client"를 추가하고, 경계를 가능한 한 낮게(리프 수준으로) 유지하십시오.
  • 파일/모듈당 하나의 책임; 라우트의 서버 액션은 actions/ 또는 라우트 옆의 _actions.ts 파일에 배치하고, 거대한 페이지 파일에 인라인으로 배치하지 마십시오.
  • 아키텍처 규칙: 각 로직 유형을 한 곳에 유지하십시오. 데이터 액세스는 lib/db, 변이는 actions/, 공유 UI는 components/, 교차 절단 헬퍼는 lib/에 배치합니다. 프로젝트의 기존 명명 규칙(파일 케이싱, 컴포넌트 명명)을 따르고 중간에 새로운 규칙을 도입하지 마십시오.
  • 코드 리뷰: 모든 중요하지 않은 변경 사항을 PR 규모로 취급하십시오. 리뷰를 요청하기 전에 명확한 diff, lint/typecheck/테스트 통과, 변경 사항과 이유에 대한 설명이 있어야 합니다. 리뷰 시(인간 또는 AI 지원), 단순히 작동 여부뿐만 아니라 누락된 인증 검사, 처리되지 않은 오류, 규칙 이탈 여부를 확인하십시오.

3. 렌더링, 데이터 및 성능

  • 정적 vs 동적 렌더링: 기본값은 정적; 라우트가 진정으로 요청별 데이터가 필요한 경우에만 동적(export const dynamic = 'force-dynamic', cookies(), headers())을 선택합니다.
  • 데이터 가져오기: 서버 컴포넌트에서 직접 가져오십시오. 변이에는 서버 액션을 사용하고, 소비자가 외부 클라이언트가 아닌 한 API 라우트에 대한 클라이언트 측 fetch는 사용하지 마십시오.
  • 스트리밍 및 Suspense: 느리거나 스트리밍 가능한 섹션을 실제 스켈레톤 폴백(단순한 스피너가 아닌)이 있는 <Suspense>로 감싸서 나머지 페이지를 렌더링하고 즉시 스트리밍할 수 있도록 하십시오. 이것이 loading.tsx가 라우트 수준에서 제공하는 기능이기도 합니다.
  • 캐싱 및 재검증: 비용이 많이 드는 읽기에는 use cache / unstable_cache(Next 버전에 따라)를 사용하십시오. 변이 후에는 force-dynamic을 사용하여 "수정"하기보다 revalidatePath / revalidateTag로 정밀하게 무효화하십시오.
  • 프리페칭: 사용자가 클릭할 가능성이 있는 링크를 프리페치하십시오. <Link>가 자동으로 수행합니다. 특별한 이유 없이 비활성화하지 마십시오(prefetch={false}).
  • 지연 로딩 및 코드 분할: 스크롤 아래 또는 드물게 사용되는 클라이언트 컴포넌트는 next/dynamic으로 지연 로딩하십시오. 한 페이지에만 필요한 라이브러리에서 큰 클라이언트 번들을 피하십시오.
  • 이미지 및 폰트 최적화: 래스터 이미지에는 항상 next/image를 사용하고(명시적인 width/height 또는 fill + 크기 지정 컨테이너), 폰트에는 next/font를 사용하십시오. 원시 <img> 또는 Google Fonts에 대한 <link>는 절대 사용하지 마십시오.
  • 핵심 웹 바이탈: LCP, CLS, INP를 실제 제약 조건으로 취급하십시오. 레이아웃 이동을 유발하는 늦게 나타나는 콘텐츠, 크기가 지정되지 않은 미디어, 차단 동기 스크립트를 사용하지 마십시오.

4. UI

  • 스타일링에는 Tailwind를 사용하고, shadcn/ui 컴포넌트를 기본 프리미티브로 사용합니다. 프로젝트의 테마 토큰(CSS 변수)을 통해 사용자 정의하며, 파일 전체에 흩어진 일회성 인라인 재정의는 사용하지 마십시오.
  • 아이콘에는 react-icons를 사용합니다(프로젝트당 하나의 아이콘 세트 선택, 예: react-icons/lu 또는 /hi2, 일관성 유지).
  • 애니메이션에는 Motion(motion.dev, 구 Framer Motion)을 사용합니다. 애니메이션 컴포넌트는 클라이언트 측에서 작고 유지하며, prefers-reduced-motion을 존중합니다.
  • 기본적으로 반응형으로 디자인합니다(모바일 우선 Tailwind 중단점). 데스크톱 전용 레이아웃을 제공하지 마십시오.

5. 폼 및 검증

  • 폼/데이터 형태당 하나의 Zod 스키마를 정의합니다. 클라이언트 검증(@hookform/resolvers/zod 사용)과 서버 액션 내부의 서버 측 검증에 동일한 스키마를 재사용하십시오. 클라이언트 전용 검증을 절대 신뢰하지 마십시오.
  • React Hook Form(useForm)이 클라이언트 상태를 관리합니다. 제출 시 서버 액션을 호출하고, 액션의 구조화된 반환 값(일반 오류로 끝나는 예외가 아닌)에서 필드 오류를 표시합니다.
  • 시작 시 Zod 스키마(lib/env.ts)로 process.env 자체를 검증하여 누락되거나 잘못된 구성이 처음 사용 시가 아닌 빠르게 실패하도록 합니다.

6. 데이터베이스 (PostgreSQL + Drizzle)

  • 스키마는 lib/db/schema.ts에 위치합니다(또는 도메인별로 분할). 마이그레이션은 drizzle-kit generate로 생성되고 drizzle-kit migrate로 적용됩니다. 생성된 마이그레이션 파일을 수동으로 편집하지 마십시오.
  • 서버리스/엣지 컨텍스트에서는 풀링된 연결(예: 드라이버 풀 또는 Neon/Supabase 풀링과 같은 공급자 사용)을 사용하십시오. 풀링 없이 요청당 새 클라이언트를 열지 마십시오.
  • 쿼리 최적화 및 N+1 방지: Drizzle의 관계형 쿼리(db.query.x.findMany({ with: {...} })) 또는 명시적 조인을 사용하여 행별로 반복하고 쿼리하지 마십시오. select * 스타일의 전체 행 가져오기 대신 필요한 열만 선택하십시오. 무한 결과 집합을 반환할 수 있는 쿼리는 페이지네이션/제한을 적용하십시오.
  • WHERE/ORDER BY/조인에 사용되는 열을 인덱싱하십시오. 스키마에 추가하고, 나중에 생각나서 추가하지 마십시오.
  • 프로덕션 데이터베이스에 대한 백업/복원 절차를 문서화하십시오(최소 관리형 공급자 스냅샷). 사용자의 설정에 이 내용이 없으면 언급하십시오.

7. 인증 및 보안

  • Better Auth를 인증에 사용합니다(세션, OAuth 제공자, 이메일/비밀번호 필요에 따라). 비밀번호 해싱이나 세션 토큰을 직접 구현하지 마십시오.
  • RBAC: 역할/권한을 명시적으로 모델링하고(role 열 + 작은 권한 검사 헬퍼), 서버 액션 / 데이터 액세스 계층에서 권한 부여를 적용하고 UI를 숨기는 것만으로는 충분하지 않습니다. 숨겨진 버튼은 접근 제어가 아닙니다.
  • 민감한 엔드포인트(인증, 폼 제출, 비용이 많이 드는 모든 것)를 속도 제한합니다. 예: Upstash Redis 또는 이에 상응하는 토큰 버킷/슬라이딩 윈도우 제한기 사용.
  • 보안 헤더 설정(next.config.js 헤더 또는 미들웨어를 통해): Content-Security-Policy, X-Frame-Options, Referrer-Policy, Permissions-Policy, Strict-Transport-Security.
  • 모든 인증/세션 쿠키에 대해 httpOnly, secure, sameSite: 'lax'(또는 가능한 경우 'strict')를 설정합니다.
  • 모든 외부 입력(폼 데이터, 쿼리 매개변수, 웹훅 페이로드)을 비즈니스 로직이나 데이터베이스에 도달하기 전에 경계에서 Zod로 검증합니다.
  • 비밀, 토큰 또는 자격 증명을 포함하는 전체 요청 본문을 절대 로깅하지 마십시오.

8. SEO

  • 라우트당 Metadata API(generateMetadata / 정적 metadata 내보내기)를 사용합니다. 제목, 설명, Open Graph, Twitter 카드.
  • 하드코딩된 오래된 목록이 아닌 실제 라우트 데이터에서 생성된 app/sitemap.ts 및 app/robots.ts를 제공합니다.
  • 메타데이터 alternates.canonical을 사용하여 정식 URL을 설정합니다. 특히 여러 쿼리 문자열 변형을 통해 도달할 수 있는 라우트의 경우.
  • 이점이 있는 콘텐츠 유형(기사, 제품, 이동 경로, 조직)에 대해 type="application/ld+json"이 있는 스크립트 태그를 사용하여 JSON-LD 구조화된 데이터를 추가합니다.

9. 접근성

  • 먼저 시맨틱 HTML(button, nav, main, header, label)을 사용합니다. 시맨틱 HTML으로는 다룰 수 없는 실제 격차를 메우기 위해서만 ARIA를 사용합니다.
  • 모든 요소는 키보드만으로 도달하고 조작할 수 있어야 합니다. 포커스 상태를 시각적으로 표시합니다. (:focus-visible 아웃라인을 대체하지 않고 제거하지 마십시오.)
  • 모든 이미지는 의미 있는 alt 속성을 가져야 합니다. (진정으로 장식용 이미지에만 빈 alt="" 사용.)
  • 모든 폼 입력에는 실제 연결된 <label>이 있어야 합니다. (플레이스홀더만으로는 부족합니다.)
  • 텍스트 및 대화형 요소에 대해 최소 WCAG AA 수준의 색상 대비를 확인하십시오.

10. 오류 처리 및 로딩 상태

실패하거나 시간이 걸릴 수 있는 모든 라우트 세그먼트는 다음을 포함해야 합니다:

  • error.tsx — 재시도 동작이 있는 세그먼트 수준 오류 경계.
  • global-error.tsx — error.tsx가 잡을 수 없는 오류에 대한 최상위 폴백.
  • not-found.tsx — 404의 경우, 데이터 조회의 notFound() 호출 포함.
  • loading.tsx — Suspense 폴백; 단순한 스피너가 아닌 최종 레이아웃과 일치하는 실제 스켈레톤으로 만드십시오.

11. 테스트

  • 단위 테스트(순수 함수, 스키마 검증, 유틸리티 로직) 및 컴포넌트 테스트(React Testing Library)에는 Vitest를 사용합니다. *.test.ts(x) 또는 __tests__/ 아래에 배치합니다.
  • 엔드 투 엔드 흐름(인증, 중요한 사용자 여정, 폼 제출)에는 Playwright를 사용합니다. 프리뷰 배포 또는 로컬 빌드에 대해 실행하고 프로덕션에 대해서는 실행하지 마십시오.
  • 새로운 서버 액션 및 검증 스키마는 최소한 기본 테스트와 함께 제공되어야 합니다. 중요한 비즈니스 로직이 기본적으로 테스트되지 않은 상태로 남지 않도록 하십시오.

12. 모니터링 및 로깅

  • 클라이언트와 서버 모두에서 오류 추적을 위해 Sentry를 사용합니다(계측 파일 + sentry.client.config / sentry.server.config), 배포 시 소스 맵을 업로드합니다.
  • 임시 console.log 대신 구조화된 로깅(요청 ID, 라우트, 사용 가능한 경우 사용자 ID가 포함된 JSON 로그)을 사용합니다.
  • 프로덕션에서 핵심 웹 바이탈을 추적하고(Vercel Analytics 또는 Sentry Performance) 배포된 URL에 가동 시간 모니터링을 설정합니다.

13. DevOps

  • 규칙적이고 범위가 지정된 커밋과 함께 Git을 사용합니다. 보호된 main 브랜치.
  • 모든 PR에 대한 GitHub Actions CI: 설치 → 린트 → 타입체크 → 단위 테스트 → 빌드 (더 큰 변경 사항에는 e2e 추가).
  • Vercel에 배포합니다. 모든 PR은 병합 전에 프리뷰 배포를 받습니다.
  • 환경 변수는 Vercel에서 환경별로 관리되며, §5의 Zod env 스키마를 통해 부팅 시 검증됩니다.

14. 미디어

  • 사용자가 업로드한/동적 미디어에는 Cloudinary를 사용합니다. 서명되고 서버에서 발급된 업로드 매개변수를 통해 업로드하고 (API 시크릿을 클라이언트 측에 노출하지 않음) Cloudinary의 변환 URL을 통해 제공하며, 크기 조정을 다시 구현하지 않습니다.

15. Claude 작업 규칙

이 스택을 사용하는 프로젝트에서 기능 추가 요청을 받으면:

  1. 새로 만들기 전에 기존 스키마/액션/컴포넌트를 확인하십시오. 확장하고 중복을 피하십시오.
  2. 새 DB 필드 → schema.ts 업데이트, 마이그레이션 생성, SQL 수동 편집 금지.
  3. 새 폼 → Zod 스키마 → RHF 폼 → 서버 측 재검증 및 권한 부여 검사가 있는 서버 액션.
  4. 새 라우트 → 정적 vs 동적 의도적으로 결정; loading.tsx/error.tsx가 없으면 추가; 메타데이터 추가.
  5. 변이 후, 영향을 받는 특정 경로/태그를 재검증하십시오. 전체 앱을 무분별하게 재검증하지 마십시오.
  6. 코드를 제시하기 전에 엄격 모드에 대해 lint/typecheck를 정신적으로 실행하십시오. any, 확인되지 않은 입력, 누락된 인증 검사가 있으면 조용히 제시하지 말고 표시하십시오.
  7. 섹션 0의 도구를 도입, 교체 또는 건너뛰기 전에 옵션과 함께 사용자에게 물어보십시오 (섹션 0의 "권장, 엄격하지 않음" 규칙 참조).

16. 동반 규칙 파일

  • AGENTS.md — 프로젝트 워크플로 규칙(메인 플로우, 기능 플로우, 승인 게이트 등).

관련 스킬