안녕하세요, 제가 처음 Next.js 프로젝트를 시작했을 때 ESLint와 Prettier를 제대로 설정하지 않아 프로젝트 후반에 일관성 없는 코드로 고생했던 경험이 있습니다. 구글링을 해도 설정법이 제각각이라 혼란스러웠고, 결국 직접 시행착오를 거치며 최적의 설정법을 찾아냈습니다. 오늘은 Next.js 프로젝트에서 ESLint와 Prettier를 효율적으로 설정하는 방법을 공유하려고 합니다.

목차
ESLint와 Prettier가 필요한 이유
프로젝트를 시작할 때 린팅과 포매팅 설정을 건너뛰고 싶은 유혹이 들죠. "나중에 하지 뭐" 하면서요. 하지만 코드베이스가 커질수록 이 결정은 큰 후회로 돌아옵니다. 제 경우엔 4개월 차에 코드 일관성 부재로 기능 추가가 점점 어려워졌고, 결국 2주를 투자해 전체 코드를 재포맷팅한 쓰라린 경험이 있습니다.
ESLint와 Prettier를 도입하면 다음과 같은 명확한 이점이 있습니다.
- 코드 품질 향상 (버그 조기 발견)
- 팀 내 코드 스타일 일관성 유지
- 코드 리뷰 시간 단축 (사소한 포맷팅 이슈로 시간 낭비 방지)
- 신규 개발자 온보딩 시간 단축
- 자동화를 통한 개발자 생산성 향상
ESLint vs Prettier: 차이점 이해하기
처음에는 ESLint와 Prettier의 차이점이 헷갈릴 수 있어요. "두 도구 다 코드 스타일 관련 아냐?" 라고 생각할 수 있는데, 실제로는 목적과 기능이 다릅니다.
기능 | ESLint | Prettier |
---|---|---|
주요 목적 | 코드 품질 검사 및 버그 방지 | 코드 스타일 일관성 유지 |
검사 영역 | 문법 오류, 안티 패턴, 잠재적 버그 | 들여쓰기, 줄바꿈, 공백, 따옴표 등 |
규칙 설정 | 고도로 커스터마이징 가능 | 최소한의 설정만 허용 (의견이 적을수록 좋음) |
자동 수정 | 일부 규칙만 자동 수정 가능 | 모든 스타일 이슈 자동 수정 |
언어 지원 | JavaScript, TypeScript 특화 | 다양한 언어 지원 (JS, TS, CSS, HTML, JSON 등) |
결론적으로, ESLint는 코드의 논리적 오류와 잠재적 버그를 찾아주고, Prettier는 코드를 일관된 스타일로 자동 정리해 줍니다. 두 도구는 경쟁 관계가 아니라 상호 보완적인 관계입니다.
Next.js 프로젝트에 기본 설정하기
Next.js 프로젝트에 ESLint와 Prettier를 설정하는 방법을 단계별로 알아보겠습니다. 설정 과정은 크게 다음과 같습니다.
- 필요한 패키지 설치
- ESLint 설정 파일 생성
- Prettier 설정 파일 생성
- 두 도구 통합하기
- VS Code 설정하기
1. 필요한 패키지 설치
먼저 필요한 npm 패키지들을 설치해야 합니다.
npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser
위 명령어를 실행하면 다음 패키지들이 설치됩니다:
-
eslint
: JavaScript/TypeScript 코드 품질 검사 도구 -
prettier
: 코드 포맷터 -
eslint-config-prettier
: Prettier와 충돌하는 ESLint 규칙 비활성화 -
eslint-plugin-prettier
: Prettier를 ESLint 플러그인으로 실행 -
@typescript-eslint/eslint-plugin
: TypeScript 관련 린팅 규칙 -
@typescript-eslint/parser
: TypeScript 파서
Next.js는 이미 기본적인 ESLint 설정을 제공합니다. next lint
명령어를 실행하면 필요한 의존성을 설치하고 .eslintrc.json
파일을 생성합니다. 하지만 이 설정은 최소한의 것이므로 Prettier와 통합하려면 추가 설정이 필요합니다.
고급 설정 및 커스터마이징
기본 설정에 만족하지 않는다면, 프로젝트에 맞게 ESLint와 Prettier 설정을 커스터마이징할 수 있습니다. 유명 기업들의 설정을 참고하면 도움이 됩니다. 에어비앤비나 구글 같은 회사의 ESLint 설정은 수년간의 경험이 담겨있습니다.
ESLint 규칙 추가하기
프로젝트 요구사항에 맞게 ESLint 규칙을 추가할 수 있습니다. 다음은 좀 더 엄격한 규칙을 적용한 .eslintrc.json 예시.
{
"extends": [
"next/core-web-vitals",
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"plugins": ["@typescript-eslint", "prettier"],
"rules": {
"prettier/prettier": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error"],
"@typescript-eslint/explicit-function-return-type": ["warn"],
"@typescript-eslint/no-explicit-any": ["error"],
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"react/prop-types": "off"
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"settings": {
"react": {
"version": "detect"
}
}
}
Prettier 옵션 커스터마이징
팀의 코드 스타일 선호도에 맞게 Prettier 설정을 조정할 수 있습니다. 다음은 자주 사용하는 Prettier 옵션
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "auto"
}
옵션 | 설명 | 기본값 | |
---|---|---|---|
semi |
semi |
문장 끝에 세미콜론 사용 여부 | true |
tabWidth |
들여쓰기 공백 수 | 2 | |
printWidth |
한 줄의 최대 길이 | 80 | |
singleQuote |
작은따옴표 사용 여부 | false | |
trailingComma |
객체/배열 마지막 요소 뒤 콤마 사용 여부 | "es5" |
특정 파일 무시하기
프로젝트 내 일부 파일이나 디렉토리에 린팅과 포매팅 적용을 제외하고 싶을 수 있습니다. 이 경우 루트 디렉토리에 .eslintignore
와 .prettierignore
파일을 추가하면 됩니다.
# .eslintignore와 .prettierignore에 공통으로 사용할 수 있는 내용
node_modules
.next
out
public
**/*.json
**/*.md
yarn.lock
package-lock.json
.github
.vscode
Git Hooks로 자동화하기
아무리 좋은 도구가 있어도 개발자가 사용하지 않으면 의미가 없죠. 그렇다고 팀원 모두에게 커밋 전에 린트와 포맷을 수동으로 실행하라고 강제하기도 어렵습니다. Git Hook을 활용하면 이 과정을 자동화할 수 있습니다.
Husky와 lint-staged 설정하기
Husky는 Git Hooks를 쉽게 설정할 수 있게 해주고, lint-staged는 스테이징된 파일에만 명령을 실행합니다. 이 조합은 커밋 전에 코드 검사와 포맷팅을 자동화하는 데 이상적입니다.
- 먼저 필요한 패키지를 설치합니다:
npm install --save-dev husky lint-staged
- package.json에 lint-staged 설정을 추가합니다
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md}": [
"prettier --write"
]
}
}
- Husky를 초기화하고 pre-commit 훅을 설정합니다
npx husky-init && npm install # Husky 초기화
npx husky add .husky/pre-commit "npx lint-staged" # pre-commit 훅 추가
npm 스크립트 추가하기
package.json 파일에 편리한 스크립트를 추가하면 개발자가 명령어를 쉽게 실행할 수 있습니다:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "next lint --fix",
"format": "prettier --write .",
"check-format": "prettier --check .",
"check-types": "tsc --noEmit"
}
}
이렇게 설정하면 다음 명령어를 실행할 수 있습니다:
-
npm run lint
: ESLint 실행 -
npm run lint:fix
: ESLint 실행하고 수정 가능한 문제 자동 수정 -
npm run format
: Prettier로 전체 프로젝트 포맷팅 -
npm run check-format
: Prettier로 포맷팅 문제 확인만 하기 -
npm run check-types
: TypeScript 타입 검사
흔한 문제 해결하기
ESLint와 Prettier를 설정하는 과정에서 몇 가지 일반적인 문제가 발생할 수 있습니다. 이러한 문제들에 대한 해결책을 알아보겠습니다.
ESLint와 Prettier 규칙 충돌
가장 흔한 문제는 ESLint와 Prettier의 규칙이 충돌하는 것입니다. 이는 eslint-config-prettier
로 해결할 수 있지만, 제대로 설정되지 않았다면 다음을 확인하세요:
- ESLint 설정에서 "prettier"가 extends 배열의 마지막에 있는지 확인하세요.
- plugins 배열에 "prettier"가 있고 rules에 "prettier/prettier": "error"가 설정되어 있는지 확인하세요.
- 명시적으로 Prettier와 충돌하는 ESLint 규칙을 비활성화했는지 확인하세요.
Husky 훅이 실행되지 않는 문제
Husky 훅이 제대로 작동하지 않는다면?
-
.husky 디렉토리의 훅 파일에 실행 권한이 있는지 확인 (Unix 기반 시스템에서):
chmod +x .husky/pre-commit
- package.json의 "lint-staged" 설정이 올바른지 확인
-
Husky를 다시 초기화:
npx husky-init && npm install
린팅과 포매팅은 CI/CD 파이프라인에 통합하는 것이 좋습니다. GitHub Actions에서는 다음과 같이 설정할 수 있습니다
name: Lint & Format Check on: [push, pull_request] jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: node-version: '18' - run: npm ci - run: npm run lint - run: npm run check-format - run: npm run check-types
매번 수동으로 린트와 포맷팅을 실행하는 것은 번거롭습니다. VS Code를 사용한다면 파일 저장 시 자동으로 포맷팅되도록 설정할 수 있습니다. 프로젝트 루트에 .vscode 폴더를 만들고 그 안에 settings.json 파일을 생성합니다.
{ "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" } }
실용적인 코드 예제: 전체 Next.js 설정
이제 실제로 활용할 수 있는 Next.js 프로젝트의 전체 ESLint 및 Prettier 설정 예제를 살펴보겠습니다. 이 예제는 TypeScript를 사용하는 Next.js 프로젝트를 기준으로 합니다.
먼저 프로젝트 구조입니다:
my-nextjs-project/
├── .eslintrc.json
├── .prettierrc
├── .prettierignore
├── .eslintignore
├── .vscode/
│ └── settings.json
├── .husky/
│ └── pre-commit
├── package.json
├── tsconfig.json
└── src/
├── pages/
├── components/
├── styles/
└── types/
.eslintrc.json
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2020,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"env": {
"browser": true,
"node": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"next/core-web-vitals",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:jsx-a11y/recommended",
"prettier"
],
"plugins": [
"react",
"@typescript-eslint",
"import",
"jsx-a11y",
"react-hooks",
"prettier"
],
"rules": {
"prettier/prettier": "error",
"no-console": ["warn", { "allow": ["warn", "error", "info"] }],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "warn",
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"jsx-a11y/anchor-is-valid": [
"error",
{
"components": ["Link"],
"specialLink": ["hrefLeft", "hrefRight"],
"aspects": ["invalidHref", "preferButton"]
}
],
"import/order": [
"error",
{
"groups": ["builtin", "external", "internal", "parent", "sibling", "index"],
"newlines-between": "always",
"alphabetize": { "order": "asc", "caseInsensitive": true }
}
]
},
"settings": {
"react": {
"version": "detect"
},
"import/resolver": {
"typescript": {},
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
}
}
.prettierrc
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "es5",
"jsxSingleQuote": false,
"bracketSpacing": true,
"jsxBracketSameLine": false,
"arrowParens": "always",
"endOfLine": "auto"
}
.prettierignore
# 빌드 산출물
.next/
out/
build/
dist/
# 의존성
node_modules/
# 로그
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# 기타 파일
.git/
.gitignore
*.md
*.lock
pnpm-lock.yaml
# 환경 설정
.env*
# Next.js 설정
next.config.js
next-env.d.ts
# 정적 파일
public/
.eslintignore
# 빌드 산출물
.next/
out/
build/
dist/
# 의존성
node_modules/
# 설정 파일
next.config.js
next-env.d.ts
babel.config.js
postcss.config.js
tailwind.config.js
jest.config.js
# 정적 파일
public/
assets/
*.svg
*.ico
*.json
*.md
*.lock
pnpm-lock.yaml
package.json (scripts 부분)
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"lint:fix": "next lint --fix",
"format": "prettier --write .",
"check-format": "prettier --check .",
"check-types": "tsc --noEmit",
"prepare": "husky install"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --cache --fix",
"prettier --write"
],
"*.{json,css,scss,md}": [
"prettier --write"
]
}
}
.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"typescript.tsdk": "node_modules/typescript/lib",
"files.eol": "\n"
}
이 설정으로 Next.js 프로젝트에서 ESLint와 Prettier를 효과적으로 활용할 수 있습니다. 특히 TypeScript와 React를 사용하는 프로젝트에서 코드 품질을 유지하고 일관된 스타일을 적용하는 데 도움이 됩니다.
이제 아래 코드 예제에서 두 가지 버전을 비교해봅시다. 첫 번째는 포맷팅이 적용되지 않은 코드이고, 두 번째는 ESLint와 Prettier를 적용한 코드입니다.
포맷팅 전 (components/Button.tsx)
import React from 'react'
type ButtonProps = {
onClick?: () => void;
children: React.ReactNode;
disabled?: boolean;
variant?: 'primary'|'secondary'|"tertiary";
size?: 'small' | 'medium' | 'large'
}
const Button = ({onClick, children, disabled=false, variant="primary",size='medium'}: ButtonProps) => {
let className = "rounded-md font-medium"
if (variant === 'primary') {
className += ' bg-blue-500 text-white hover:bg-blue-600'
} else if(variant==='secondary'){
className += ' bg-gray-200 text-gray-800 hover:bg-gray-300'
}else{
className += ' bg-transparent text-blue-500 hover:text-blue-600'
}
switch(size) {
case 'small':
className += ' py-1 px-2 text-sm'
break;
case 'medium':
className += ' py-2 px-4 text-base'
break;
case 'large':
className += ' py-3 px-6 text-lg'
break;
default:
className += ' py-2 px-4 text-base'
}
return (
)
}
포맷팅 후 (components/Button.tsx)
import React from 'react';
type ButtonProps = {
onClick?: () => void;
children: React.ReactNode;
disabled?: boolean;
variant?: 'primary' | 'secondary' | 'tertiary';
size?: 'small' | 'medium' | 'large';
};
const Button = ({
onClick,
children,
disabled = false,
variant = 'primary',
size = 'medium',
}: ButtonProps) => {
let className = 'rounded-md font-medium';
if (variant === 'primary') {
className += ' bg-blue-500 text-white hover:bg-blue-600';
} else if (variant === 'secondary') {
className += ' bg-gray-200 text-gray-800 hover:bg-gray-300';
} else {
className += ' bg-transparent text-blue-500 hover:text-blue-600';
}
switch (size) {
case 'small':
className += ' py-1 px-2 text-sm';
break;
case 'medium':
className += ' py-2 px-4 text-base';
break;
case 'large':
className += ' py-3 px-6 text-lg';
break;
default:
className += ' py-2 px-4 text-base';
}
return (
);
};
export default Button;
마무리
Next.js 프로젝트에서 ESLint와 Prettier를 설정하는 과정을 살펴봤습니다. 이 두 도구를 적절히 설정하면 개발자 경험이 크게 향상되고 코드 품질도 일관되게 유지할 수 있습니다. 개인적으로 프로젝트 초기에 이런 설정을 해두면 추후 발생할 수 있는 많은 문제를 예방할 수 있다고 생각합니다.
기억해야 할 핵심 사항들은 다음과 같습니다:
- ESLint와 Prettier는 각각 다른 목적을 가진 도구입니다. ESLint는 코드 품질을 검사하고, Prettier는 코드 스타일을 일관되게 유지합니다.
- 두 도구를 함께 사용하려면 충돌을 방지하기 위한 추가 설정이 필요합니다.
- Git Hooks를 통해 커밋 전에 자동으로 코드를 검사하고 수정할 수 있습니다.
- VS Code 설정을 통해 파일 저장 시 자동 포맷팅을 적용할 수 있습니다.
- CI/CD 파이프라인에 린팅과 포맷팅 검사를 통합하면 품질 관리가 더욱 강화됩니다.
물론 이런 설정은 팀의 선호도와 프로젝트 요구사항에 따라 달라질 수 있습니다. 처음에는 기본 설정으로 시작하고, 필요에 따라 규칙을 조정하는 것이 좋습니다. 지나치게 많은 규칙을 적용하면 오히려 개발자들의 불만을 살 수도 있으므로 균형 잡힌 접근이 중요합니다.
마지막으로, ESLint와 Prettier 설정은 한 번으로 끝나는 것이 아닙니다. 새로운 패턴이나 기술이 도입될 때마다 규칙을 업데이트하고, 팀 피드백을 반영하여 지속적으로 개선해야 합니다. 이 과정이 번거롭게 느껴질 수 있지만, 장기적으로는 높은 품질의 코드베이스를 유지하는 데 큰 도움이 됩니다..
'Developer > Web Frontend' 카테고리의 다른 글
[Next.js] 컴포넌트 재사용 (0) | 2025.04.04 |
---|---|
[Next.js] 첫 웹 애플리케이션 만들기. Hello World 페이지 (0) | 2025.04.03 |
[Next.js] app.js와 _document.js의 역할과 차이점 (0) | 2025.04.02 |
[Next.js] 동적 라우팅 (0) | 2025.04.02 |
[Next.js] Next.js 서버 사이드 렌더링(SSR) (0) | 2025.04.01 |