Tips & Tricks (업데이트: 2026. 6. 2.)

Claude Code로 ESLint Flat Config 실무 설정하기

Claude Code로 ESLint Flat Config를 구성하고 TypeScript, React, Astro, CI, 수정 프롬프트까지 정리합니다.

Claude Code로 ESLint Flat Config 실무 설정하기

ESLint 설정을 Claude Code에 막연히 맡기지 않는다

ESLint는 JavaScript와 TypeScript 코드를 실행하기 전에 검사하는 정적 분석 도구입니다. 정적 분석은 앱을 띄우기 전에 위험한 비동기 처리, React Hooks 실수, 접근성 누락, 일관성 없는 import를 찾아내는 과정입니다.

ESLint v9 이후 Flat Config가 표준 흐름이 되었고, 2026년 6월 기준 공식 문서도 eslint.config.jseslint.config.mjs를 중심으로 설명합니다. 하지만 Claude Code에 “ESLint 설정해줘”라고만 요청하면 오래된 .eslintrc 방식, 타입 정보를 쓰지 않는 느슨한 설정, CI만 느려지는 과한 규칙이 섞이기 쉽습니다.

더 좋은 방식은 Claude Code에 명확한 조건을 주는 것입니다. 사용하는 스택, 생성물 디렉터리, 반드시 통과해야 할 명령, 테스트에서만 완화할 규칙을 먼저 정합니다. 이 글은 Masa가 React 관리자 화면, Astro 콘텐츠 사이트, TypeScript 라이브러리에서 사용한 패턴을 기준으로 정리했습니다.

기준 문서는 ESLint Configuration Files, typescript-eslint typed linting, eslint-plugin-astro User Guide, Claude Code CLI reference입니다.

의존성과 scripts를 먼저 고정한다

Claude Code가 파일을 수정하기 전에 필요한 패키지를 설치합니다. 기본 세트는 ESLint, TypeScript, React, Hooks, 접근성, import 정렬을 포함합니다. .astro 파일이 있는 프로젝트에서만 Astro 플러그인을 추가합니다.

npm i -D eslint @eslint/js typescript typescript-eslint globals
npm i -D eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y
npm i -D eslint-plugin-simple-import-sort

# Astro 프로젝트에만 추가
npm i -D eslint-plugin-astro astro-eslint-parser

package.json에는 로컬 수정용과 CI 검증용 명령을 나눠 넣습니다. --max-warnings=0은 경고도 실패로 처리합니다. 기존 코드가 많은 프로젝트라면 첫 정리 후에 켜는 편이 안전합니다.

{
  "scripts": {
    "lint": "eslint . --max-warnings=0",
    "lint:fix": "eslint . --fix",
    "lint:debug": "eslint --print-config src/App.tsx > .eslint-debug.json",
    "typecheck": "tsc --noEmit",
    "ci:verify": "npm run lint && npm run typecheck"
  }
}

Claude Code는 설정 파일을 만든 뒤 멈추면 안 됩니다. 팀이 실제로 실행할 검증 명령까지 같은 순서로 돌려야 합니다.

package.json scripts
  -> eslint.config.mjs
  -> npm run lint:fix
  -> npm run lint
  -> npm run typecheck
  -> CI gate
  -> Claude Code에 남은 diff 리뷰 요청

TypeScript/React용 Flat Config

React + TypeScript 앱은 아래 eslint.config.mjs에서 시작할 수 있습니다. projectService: true는 타입 정보를 쓰는 lint를 켭니다. 강력하지만 비용이 있으므로 빌드 결과물과 생성 디렉터리는 먼저 무시해야 합니다.

import js from "@eslint/js";
import globals from "globals";
import react from "eslint-plugin-react";
import reactHooks from "eslint-plugin-react-hooks";
import jsxA11y from "eslint-plugin-jsx-a11y";
import simpleImportSort from "eslint-plugin-simple-import-sort";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    ignores: [
      "node_modules/",
      "dist/",
      "build/",
      "coverage/",
      ".next/",
      ".astro/",
      "public/",
      "*.min.js"
    ]
  },
  js.configs.recommended,
  ...tseslint.configs.strictTypeChecked,
  ...tseslint.configs.stylisticTypeChecked,
  {
    files: ["**/*.{js,mjs,cjs,ts,tsx}"],
    languageOptions: {
      ecmaVersion: "latest",
      sourceType: "module",
      globals: {
        ...globals.browser,
        ...globals.node,
        ...globals.es2024
      },
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    }
  },
  {
    files: ["**/*.{jsx,tsx}"],
    ...react.configs.flat.recommended,
    settings: {
      react: { version: "detect" }
    },
    rules: {
      ...react.configs.flat.recommended.rules,
      "react/react-in-jsx-scope": "off",
      "react/prop-types": "off"
    }
  },
  {
    files: ["**/*.{jsx,tsx}"],
    plugins: {
      "react-hooks": reactHooks,
      "jsx-a11y": jsxA11y
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      ...jsxA11y.configs.recommended.rules
    }
  },
  {
    plugins: {
      "simple-import-sort": simpleImportSort
    },
    rules: {
      "simple-import-sort/imports": "error",
      "simple-import-sort/exports": "error",
      "@typescript-eslint/consistent-type-imports": [
        "error",
        { prefer: "type-imports", fixStyle: "separate-type-imports" }
      ],
      "@typescript-eslint/no-floating-promises": "error",
      "@typescript-eslint/no-misused-promises": [
        "error",
        { checksVoidReturn: { attributes: false } }
      ],
      "@typescript-eslint/no-unused-vars": [
        "error",
        { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }
      ],
      "no-console": ["warn", { allow: ["warn", "error"] }]
    }
  },
  {
    files: ["**/*.{js,mjs,cjs}"],
    extends: [tseslint.configs.disableTypeChecked]
  },
  {
    files: ["**/*.{test,spec}.{ts,tsx}", "**/__tests__/**/*.{ts,tsx}"],
    rules: {
      "@typescript-eslint/no-explicit-any": "off",
      "@typescript-eslint/no-unsafe-assignment": "off",
      "@typescript-eslint/no-unsafe-member-access": "off"
    }
  }
);

이 설정의 목적은 취향보다 실제 위험을 줄이는 것입니다. no-floating-promisesawait 누락을 잡고, no-misused-promises는 JSX 이벤트 핸들러의 위험한 Promise 사용을 줄입니다. 테스트 파일만 일부 완화하고 운영 코드는 엄격하게 유지하는 점이 중요합니다.

Astro는 .astro 파일을 별도로 다룬다

Astro 파일은 템플릿, TypeScript frontmatter, 컴포넌트 호출, 클라이언트 스크립트가 섞입니다. React용 설정을 그대로 적용하면 .astro 파싱 단계에서 실패하기 쉽습니다.

Astro 콘텐츠 사이트라면 플러그인의 Flat 추천 설정을 먼저 펼치고, .astro 전용 규칙을 추가합니다. 특히 astro/no-set-html-directive는 블로그나 문서 사이트에서 HTML 주입을 놓치지 않게 도와줍니다.

import js from "@eslint/js";
import astro from "eslint-plugin-astro";
import globals from "globals";
import tseslint from "typescript-eslint";

export default tseslint.config(
  {
    ignores: ["dist/", ".astro/", "node_modules/", "public/"]
  },
  js.configs.recommended,
  ...astro.configs["flat/recommended"],
  ...astro.configs["jsx-a11y-recommended"],
  ...tseslint.configs.recommendedTypeChecked,
  {
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node
      },
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    }
  },
  {
    files: ["**/*.astro"],
    languageOptions: {
      parserOptions: {
        parser: tseslint.parser,
        extraFileExtensions: [".astro"],
        projectService: true,
        tsconfigRootDir: import.meta.dirname
      }
    },
    rules: {
      "astro/no-set-html-directive": "error",
      "astro/no-unused-define-vars-in-style": "error"
    }
  }
);

모든 포맷팅을 ESLint로 해결하려고 하지 않는 편이 좋습니다. 포맷은 Prettier에 맡기고, ESLint는 위험한 코드, 접근성, 타입 오류, 프로젝트 규칙에 집중시킵니다. 관련 내용은 Prettier 설정 가이드와 함께 보면 좋습니다.

실전 예시 3가지

예시 1은 SaaS 관리자 화면입니다. 사용자 초대, 결제 상태 변경, 권한 수정은 비동기 처리가 많습니다. 여기서 @typescript-eslint/no-floating-promiseserror가 맞습니다. 빠진 await 하나가 실제 장애로 이어질 수 있기 때문입니다.

예시 2는 Astro 기술 블로그입니다. 가장 중요한 것은 .astro 파싱, 접근성, 사용하지 않는 스타일, 위험한 HTML입니다. 생성 페이지가 많으므로 dist/, .astro/, 출력 폴더를 무시하는 설정도 필수입니다.

예시 3은 TypeScript 라이브러리입니다. 공개 API는 테스트보다 엄격해야 합니다. 타입 import, 미사용 변수, export 규칙은 본문 코드에서 유지하고, test fixture에서만 any를 허용합니다.

프로젝트강하게 둘 규칙완화할 곳
React 관리자 화면Promise, Hooks, a11yStorybook mock
Astro 블로그.astro, HTML 주입, 미사용 CSS생성 콘텐츠
TypeScript 라이브러리타입 import, 미사용 변수, exporttest fixture

커밋 전 검사까지 연결하려면 Husky + lint-staged 가이드를 참고하세요. 큰 저장소에서는 pre-commit은 빠르게, 무거운 typed lint는 CI에서 실행하는 편이 좋습니다.

CI에서 같은 명령을 실행한다

로컬에서 통과해도 CI에서 같은 명령을 실행하지 않으면 팀 품질은 유지되지 않습니다. GitHub Actions는 아래 정도면 충분합니다.

name: code-quality

on:
  pull_request:
  push:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

기존 프로젝트에서 오류가 수백 개 나온다면 전체에 eslint --fix를 한 번에 돌리지 마세요. 먼저 규칙별로 분류하고, Claude Code에는 위험도가 높은 항목부터 작은 diff로 고치라고 요청합니다.

npm run lint
npm run lint:fix
npm run lint
npm run typecheck
npm run lint:debug

lint:debug는 특정 파일에 최종 적용된 설정을 보여줍니다. React 규칙이 .astro에 잘못 적용되거나, 테스트 완화 규칙이 운영 코드에 새는 상황을 확인할 때 유용합니다.

Claude Code 요청 템플릿

템플릿 1: 새로 도입하기.

이 저장소에 ESLint Flat Config를 도입해주세요.
스택은 TypeScript + React입니다. package.json, tsconfig, 기존 lint 설정을 먼저 읽어주세요.
eslint.config.mjs를 만들고 npm run lint와 npm run typecheck가 통과할 때까지 수정해주세요.
동작을 바꿀 수 있는 자동 수정은 피하고, 필요하면 먼저 이유를 설명해주세요.

템플릿 2: lint 오류 수정.

npm run lint 결과를 붙여넣겠습니다.
오류를 규칙별로 분류하고 영향이 작은 것부터 수정해주세요.
eslint-disable은 마지막 수단으로만 쓰고, 사용하면 한 줄 이유를 남겨주세요.
수정 후 npm run lint와 npm run typecheck를 실행해주세요.

템플릿 3: Astro 대응.

이 Astro 사이트의 ESLint 설정을 검토해주세요.
.astro, .ts, .tsx에 적용되는 설정을 분리하고 eslint-plugin-astro의 Flat 추천 설정을 사용해주세요.
astro/no-set-html-directive를 error로 설정하고 React 규칙이 .astro 전체에 잘못 적용되지 않는지 확인해주세요.

템플릿 4: CI 실패 조사.

GitHub Actions의 lint job이 실패했습니다.
로컬과 CI의 Node, npm, ESLint, 플러그인 버전 차이를 비교해주세요.
재현 명령을 만든 뒤 설정 변경, 의존성 업데이트, 소스 수정 중 무엇이 필요한지 나눠서 제안해주세요.
가장 작은 안전한 diff로 고쳐주세요.

Claude Code에는 “lint 고쳐줘”보다 “운영 규칙은 약하게 만들지 말고, 이 명령으로 증명해줘”라고 요청하는 편이 훨씬 안전합니다.

자주 만나는 함정

첫 번째 함정은 오래된 .eslintrcextends 체인을 Flat Config에 그대로 붙이는 것입니다. 구조가 다르므로 Flat 예시를 제공하는 플러그인 문서를 우선 사용하세요.

두 번째 함정은 타입 lint를 모든 파일에 적용하는 것입니다. projectService: true는 강력하지만 생성물과 번들 파일까지 읽으면 CI가 느려집니다. ignores를 먼저 정리하세요.

세 번째 함정은 거대한 자동 수정 diff입니다. import 정렬, 타입 import, 미사용 변수, 포맷 변경이 한 번에 섞이면 실제 동작 변화가 묻힙니다. Masa는 첫 도입 때 Promise, import, 프레임워크 규칙으로 나눠 처리합니다.

네 번째 함정은 warning을 영원히 남기는 것입니다. 막지 않는 warning은 곧 아무도 보지 않는 소음이 됩니다. 정책은 error, 교육용은 잠깐 warn, 신호가 약하면 규칙을 넣지 않습니다.

다섯 번째 함정은 Claude Code에 의도를 말하지 않는 것입니다. 접근성을 낮추면 안 되는지, test fixture의 any를 허용하는지, 공개 API를 더 엄격히 볼지 알려줘야 현장에 맞는 설정이 나옵니다.

정리

ESLint Flat Config는 설정을 한 파일에 모아 규칙의 적용 범위를 보기 쉽게 만듭니다. Claude Code의 가치는 파일을 한 번 생성하는 것이 아니라, 현재 코드베이스를 읽고 검증 명령을 실행하며 기준을 약화시키지 않고 조정하는 데 있습니다.

React/TypeScript와 Astro 중 올바른 기준을 고르고, npm run lintnpm run typecheck를 CI에 넣으세요. 이후에는 템플릿으로 Claude Code에 작은 수정과 검증을 요청하고, eslint-disable과 큰 --fix diff는 사람이 리뷰합니다.

다음 단계로는 Prettier 설정Husky + lint-staged를 연결하면 좋습니다. 재사용 가능한 리뷰 프롬프트와 도입 체크리스트가 필요하면 ClaudeCodeLab 제품 페이지도 확인할 수 있습니다.

실제로 테스트한 결과

Masa는 이 설정을 작은 React 관리자 화면과 Astro 블로그 템플릿에 넣어 검증했습니다. 첫 실행에서는 import 순서와 처리되지 않은 Promise가 많이 나왔습니다. 한 번의 eslint --fix diff는 리뷰하기 어려웠고, Promise, import, Astro 안전 규칙 순서로 나누는 방식이 더 안정적이었습니다. 최종적으로 npm run lintnpm run typecheck를 CI에 고정하고, 실패 로그를 Claude Code에 붙여 작은 수정으로 처리하는 흐름이 가장 재현성이 높았습니다.

#Claude Code #ESLint #コード品質 #TypeScript #開発環境
무료

무료 PDF: Claude Code 치트시트

이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.

개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.

Masa

작성자 소개

Masa

Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.