Next.js package.json의 scripts와 dependencies, devDependencies는 어떻게 읽나요?
package.json의 scripts는 실행 명령, dependencies와 devDependencies는 패키지 의존성을 설명합니다. npm run dev와 build·start가 어떤 작업을 하는지 실제 정의를 읽고 구분합니다.
적용 조건·범위: 기대 결과: 일반 예제의 lint나 typecheck가 모든 프로젝트에 있다고 가정하지 않습니다. Missing script가 나면 npm run 목록과 일치시키는 것이 답입니다.
독립 실습: 현재 프로젝트의 실행 명령 읽기
React 컴포넌트·TypeScript·async/await를 알고 시작합니다. Next.js 환경 준비의 루트 app/ TypeScript App Router 프로젝트를 별도 연습 폴더에서 사용합니다. 이 글의 기존 실습 기준은 Next.js 16.3.5이며 Cache Components는 끈 구성입니다. 생성된 app/layout.tsx는 유지합니다. 아래 파일은 TaskFlow·인증·DB 없이 실행하는 독립 예제입니다.
package.json에서 dev/build/start를 찾아 실제 명령 문자열을 기록합니다. npm run은 이 프로젝트에 정의된 스크립트만 목록으로 보여 줍니다. build를 먼저 성공시킨 뒤 start를 실행해 개발 실행과 비교합니다.
npm pkg get scripts
npm ls next react react-dom
npm run
기대 결과: 일반 예제의 lint나 typecheck가 모든 프로젝트에 있다고 가정하지 않습니다. Missing script가 나면 npm run 목록과 일치시키는 것이 답입니다.
자가 확인: scripts.start와 scripts.dev가 같은 프로그램을 실행하는지, lockfile과 선언 버전이 다른 역할인지를 설명합니다.
scripts
일반적인 Next.js 프로젝트의 scripts는 다음과 같습니다.
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
}
}
dev
npm run dev
개발 서버를 실행합니다.
build
npm run build
프로덕션 빌드를 생성합니다.
start
npm run start
build가 끝난 결과물을 실행합니다. 개발용 명령이 아닙니다.
dependencies와 devDependencies
앱 실행에 필요한 패키지는 보통 dependencies에 둡니다.
{
"dependencies": {
"next": "...",
"react": "...",
"react-dom": "..."
}
}
빌드·린트·타입 검사처럼 개발 도구 성격의 패키지는 devDependencies에 들어갈 수 있습니다.
{
"devDependencies": {
"typescript": "...",
"eslint": "..."
}
}
현재 버전 확인
npm ls next react react-dom
문서 예제를 사용할 때는 설치된 버전과 공식 문서 버전을 확인합니다.
package-lock.json
package-lock.json은 실제 설치된 의존성 트리를 고정하는 역할을 합니다.
협업 프로젝트에서 문제가 생겼다고 이유 없이 삭제하는 습관은 피합니다.
자주 발생하는 오류
npm run start를 바로 실행합니다
build 결과가 없다면 start가 정상 실행되지 않을 수 있습니다.
npm run build
npm run start
순서로 확인합니다.
package-lock.json을 무조건 삭제합니다
먼저 설치 오류 원인을 확인합니다.
Next.js 버전을 모르고 오래된 예제를 적용합니다
App Router의 params, cache, Proxy 같은 기능은 버전 변화가 큽니다.
선택 실습: 할 일 앱에 적용하기
TaskFlow는 작업을 추가·완료·삭제하는 할 일 앱입니다. 이 선택 실습에서는 Next.js로 페이지와 서버 기능을 확장합니다.
이번 회차는 기능 추가 없이 package.json의 dev/build/start/typecheck와 실제 설치 버전을 읽습니다.
선택: 연재 프로젝트와 전체 자료
연재 프로젝트를 이어 만드는 분을 위한 자료입니다. 이 글의 개념과 예제만 찾으셨다면 필요한 파일과 실행 방법만 펼쳐보세요.
TaskFlow Next.js 프로젝트 적용
시작 체크포인트: 이전: Next.js App Router 첫 프로젝트 만들기의 완료 상태에서 이어갑니다.
이전 회차 완료 ZIP으로 시작하기. 새 폴더에 풀어 현재 회차 완료본과 나란히 비교합니다.
이전 완료본과 달라진 파일: package.json. 아래 변경 설명을 따라 수정하고 전체 코드의 같은 파일과 대조합니다.
직접 확인: TaskFlow 경로·화면·설정
독자 질문: npm run dev와 npm run start는 같은 화면을 띄우는데 왜 구분할까요? 전자는 개발 서버, 후자는 먼저 생성한 프로덕션 빌드를 실행합니다.
- 2회차 ZIP의 프로젝트 루트에서
package.json의scripts.dev,build,start,typecheck를 읽습니다. 이 글의 완료 코드에는next build --webpack과tsc --noEmit이 있으며, 앞의 일반 예시next build와 구분합니다. 완료 코드에lintscript는 없습니다. npm install뒤npm ls next react react-dom을 실행하여 설치된 버전과package.json의 선언을 비교합니다.(empty)또는 오류라면 프로젝트 루트, 설치 로그, lockfile을 점검합니다.npm run dev를 실행하고http://localhost:3000/,/tasks,/settings를 엽니다. 각 페이지의 제목과 홈·작업·설정 링크를 확인합니다. 3000번 포트가 점유되면 터미널에 표시된 실제 포트를 사용합니다.- 개발 서버를 종료하고
npm run typecheck,npm run build,npm run start순서로 실행합니다. 빌드가 성공한 뒤에만 프로덕션 서버의 세 경로를 다시 확인합니다. - 설치 또는 설정 수정 뒤
package-lock.json변경 내용을 비교합니다. 실습 전 원본을 보관하고 lockfile을 임의 삭제해 오류를 숨기지 않습니다.
결과 기록과 오류 점검
이번 콘텐츠 편집에서 위 명령이나 브라우저·TaskFlow 서버를 실행하지 않았습니다. 따라서 세 경로의 실제 화면, 버전 일치, 타입 검사, 빌드와 프로덕션 서버 결과는 미확인입니다. 독자는 실행 날짜, Node/npm 버전, 각 명령의 종료 코드, 방문 경로와 화면 제목을 기록하세요.
Missing script는 실제 scripts 키, next: command not found는 설치 위치와 npm install 오류, 포트 충돌은 터미널의 대체 포트를 확인합니다. start에서 빌드 산출물이 없다는 오류가 보이면 먼저 build 성공 여부를 확인합니다.
스스로 확인할 문제
완료 코드에는 npm run lint와 npm run typecheck 중 무엇이 정의되어 있나요? /tasks 직접 새로고침은 언제 확인하나요? 답: typecheck입니다. 개발 서버에서 먼저 확인하고, 빌드·start가 성공했다면 프로덕션 서버에서도 다시 확인합니다.
완료 코드 ZIP 다운로드 — next-step-03-package-json
이전 체크포인트: next-step-02-app-router-base
이번 회차의 변경
이번 회차는 기능 추가 없이 package.json의 dev/build/start/typecheck와 실제 설치 버전을 읽습니다. 완료 ZIP에는 필요한 설정이 모두 포함됩니다.
이 회차는 이전 프로젝트의 실행 코드를 유지하고 설정·오류·운영 기준을 점검합니다.
전체 파일·코드 보기
실행과 검증
Node.js 22 LTS 이상 권장(Next.js 최소 20.9). 루트 app/ 구조, CSS 사용.
npm install
npm run dev
npm run build
npm run start
전체 코드와 ZIP은 같은 완료 체크포인트입니다. 자동 생성 worker는 ZIP에 포함하며 라이브러리 파일은 코드 뷰어에서 생략합니다.
완료 체크포인트: next-step-03-package-json
실습 프로젝트 전체 코드
.gitignore
node_modules
.next
.env*
!.env.example
*.tsbuildinfo
app/_components/SiteHeader.tsx
import Link from "next/link";
export default function SiteHeader() {
return (
<header>
<nav aria-label="주 메뉴">
<Link href="/">홈</Link>
<Link href="/tasks">작업</Link>
<Link href="/settings">설정</Link>
</nav>
</header>
);
}
app/globals.css
* {
box-sizing: border-box;
}
body {
margin: 0;
color: #171717;
background: #fafafa;
font-family: Arial, sans-serif;
line-height: 1.6;
}
header,
main {
width: min(880px, calc(100% - 32px));
margin: 24px auto;
}
nav {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-items: center;
}
a {
color: inherit;
text-underline-offset: 3px;
}
button,
input,
select {
min-height: 44px;
padding: 8px 12px;
font: inherit;
border: 1px solid #aaa;
background: #fff;
color: #171717;
max-width: 100%;
}
button {
cursor: pointer;
}
button:disabled {
opacity: 0.6;
cursor: wait;
}
input {
display: block;
width: 100%;
}
label {
display: block;
}
form,
section,
aside {
margin: 20px 0;
}
ul {
padding: 0;
list-style: none;
}
li {
padding: 12px;
margin: 12px 0;
border: 1px solid #ccc;
overflow-wrap: anywhere;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
.controls form {
margin: 0;
}
.modal {
width: min(640px, calc(100% - 32px));
border: 1px solid #777;
padding: 24px;
background: #fff;
color: #171717;
}
.modal::backdrop {
background: rgb(0 0 0 / 55%);
}
:focus-visible {
outline: 3px solid #555;
outline-offset: 3px;
}
[data-theme="dark"] {
background: #202020;
color: #fafafa;
padding: 16px;
}
[data-density="compact"] li {
padding: 8px;
margin: 8px 0;
}
img {
max-width: 100%;
height: auto;
}
app/layout.tsx
import type { Metadata } from "next";
import type { ReactNode } from "react";
import "./globals.css";
import SiteHeader from "./_components/SiteHeader";
export const metadata: Metadata = {
title: { default: "TaskFlow Next.js", template: "%s | TaskFlow" },
description: "서버와 브라우저 역할을 배우는 TaskFlow 학습 프로젝트",
};
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="ko">
<body>
<SiteHeader />
{children}
</body>
</html>
);
}
app/lib/data.ts
import type { Task } from "./types";
const tasks: Task[] = [
{
id: "task-1",
title: "App Router 공부",
description: "서버와 브라우저의 역할을 구분합니다.",
completed: false,
ownerId: "demo",
},
{
id: "task-2",
title: "TaskFlow 만들기",
description: "누적 실습을 완성합니다.",
completed: true,
ownerId: "demo",
},
];
export async function getTasks() {
return tasks;
}
export async function getTask(id: string) {
return tasks.find((t) => t.id === id);
}
export async function getTaskStats() {
const ts = await getTasks();
return { total: ts.length, completed: ts.filter((t) => t.completed).length };
}
app/lib/types.ts
export type Task = {
id: string;
title: string;
description: string;
completed: boolean;
ownerId: string;
};
app/page.tsx
import Link from "next/link";
export default function HomePage() {
return (
<main>
<h1>TaskFlow Next.js</h1>
<p>App Router 기반 작업 관리 서비스입니다.</p>
<Link href="/tasks">작업 목록 보기</Link>
</main>
);
}
app/settings/page.tsx
export default function SettingsPage() {
return (
<main>
<h1>설정</h1>
<p>TaskFlow 설정 화면입니다.</p>
</main>
);
}
app/tasks/page.tsx
import Link from "next/link";
import { getTasks } from "@/app/lib/data";
export default async function TasksPage() {
const tasks = await getTasks();
return (
<main>
<h1>작업 목록</h1>
<ul>
{tasks.map((task) => (
<li key={task.id}>
{task.title}
<span> · {task.completed ? "완료" : "진행 중"}</span>
</li>
))}
</ul>
</main>
);
}
next-env.d.ts
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
import "./.next/types/root-params.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
next.config.ts
import type { NextConfig } from "next";
const config: NextConfig = { cacheComponents: false };
export default config;
package.json
{
"name": "taskflow-next",
"version": "1.0.3",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build --webpack",
"start": "next start",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"next": "16.3.5",
"react": "19.3.0",
"react-dom": "19.3.0"
},
"devDependencies": {
"typescript": "5.9.3",
"@types/node": "24.13.6",
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./*"
]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}
글 소개·학습 준비·전체 목차

Next.js · 3/38 · TaskFlow 누적 실습
Next.js package.json scripts dependencies 이해
Next.js · 3 / 38 · 필수 학습 · package.json
Next.js 프로젝트에서 명령을 실행할 때 실제로 어떤 패키지와 script가 연결되는지 알아두면 환경 오류를 훨씬 빠르게 찾을 수 있습니다.
이 글에서는 package.json의 scripts, dependencies, devDependencies를 Next.js 프로젝트 기준으로 읽는 방법을 설명합니다.
이번 글에서 배우는 내용
- package.json 역할
- dev / build / start script
- dependencies와 devDependencies
- Next.js·React 버전 확인
- package-lock.json 역할
- 패키지 설치 시 변경되는 항목
목차
다음 학습
다음 글에서는 App Router의 기본값인 Server Component와 상호작용이 필요한 Client Component의 경계를 구분합니다.
공식 문서
이 글이 도움이 되었나요?
읽음 기록
읽음 — / 전체 39개 · 필수 38개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.