ESLint flat config 규칙 적용 안됨 해결: eslint.config.js 기준

2026.05.16·수정 2026.07.19·약 12분

먼저 확인할 핵심

.eslintrc에서 eslint.config.js로 옮긴 뒤 ESLint flat config 규칙 적용이 안 되는 문제를 정리합니다. flat config는 설정을 한 파일에 모아두는 것보다, 검사 대상 파일마다 어떤 설정 객체가 매칭되는지 확인하는 방식이 중요합니다. 그래서 같은 규칙을 적어도 files 범위, ignores 위치, 플러그인 등록 방식, TypeScript 설정 중 하나가 어긋나면 규칙이 없는 것처럼 보일 수 있습니다.

TypeScript 학습 시리즈에서 이어서 보기

이 주제의 앞뒤 흐름은 TypeScript 학습 로드맵에서 확인할 수 있습니다. 실무 중 만나는 대표 에러를 증상별로 비교하려면 TypeScript 오류 해결 모음을 함께 보면 좋습니다.

규칙이 안 먹는 증상부터 나누기

ESLint flat config 규칙 적용 안됨 문제를 진단하는 흐름

eslint.config.js로 바꾼 직후에는 에러가 완전히 터지는 경우보다 일부 규칙만 조용히 빠지는 경우가 더 헷갈립니다. 예를 들어 no-console은 잡히는데 React Hooks 규칙은 동작하지 않거나, JavaScript 파일은 검사되는데 .tsx 파일에서는 아무 반응이 없는 식입니다.

이때 바로 패키지를 다시 설치하거나 VS Code 설정부터 바꾸면 원인을 좁히기 어렵습니다. 먼저 ESLint가 어떤 설정 파일을 읽는지, 현재 파일이 설정 객체의 files 범위에 들어가는지, 해당 규칙을 제공하는 플러그인이 flat config 방식으로 등록되어 있는지부터 분리해서 확인해야 합니다.

기존 .eslintrc 방식에 익숙하면 extends, plugins, ignorePatterns를 거의 문자열 설정처럼 다루게 됩니다. flat config에서는 그 감각이 그대로 맞지 않습니다. 배열 안의 각 설정 객체가 어떤 파일에 걸리는지부터 봐야 실제 규칙 적용 여부를 판단할 수 있습니다.

flat config에서 먼저 봐야 하는 기준

flat config의 기본 파일은 프로젝트 루트의 eslint.config.js, eslint.config.mjs, eslint.config.cjs를 주로 사용합니다. TypeScript 설정 파일도 쓸 수 있지만 실행 환경에 따라 추가 설정이 필요할 수 있으므로, 일반적인 React 또는 Vite 프로젝트에서는 JavaScript나 MJS 파일로 시작하는 구성이 단순합니다.

핵심은 “rules에 적었는가”보다 “그 rules가 들어 있는 설정 객체가 지금 검사하는 파일과 매칭되는가”입니다. files: ['src/*.js']처럼 작성하면 src/components/Button.jsx, src/app/page.tsx, src/features/product/ProductCard.tsx 같은 하위 파일은 빠질 수 있습니다.

ignores도 위치에 따라 해석이 달라집니다. 빌드 결과물이나 커버리지 폴더처럼 전체에서 제외할 대상은 규칙이나 플러그인과 섞지 않고 제외 전용 객체로 분리하는 편이 안전합니다. 반대로 특정 설정 객체 안에서만 제외할 파일이라면 files와 함께 범위를 좁혀야 합니다.

자주 틀리는 설정 예시

아래 설정은 겉으로 보기에는 단순하지만 실제 프로젝트에서는 ESLint flat config 규칙 적용 안됨 문제가 생기기 쉽습니다. 검사 범위가 너무 좁고, flat config에서 플러그인을 문자열 배열로 넣고 있기 때문입니다.

export default [
  {
    files: ['src/*.js'],
    plugins: ['react-hooks'],
    rules: {
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn'
    }
  }
];

이 설정은 src/App.js처럼 루트 바로 아래에 있는 JavaScript 파일만 기대대로 걸릴 수 있습니다. 하지만 실제 화면 코드는 보통 src/components, src/pages, src/features처럼 여러 폴더로 나뉩니다. 파일이 한 단계만 더 들어가도 src/*.js 범위를 벗어납니다.

또 하나의 문제는 plugins입니다. flat config에서는 플러그인 이름만 문자열로 적는 방식이 아니라, import한 플러그인 객체를 원하는 namespace에 연결해야 합니다. 기존 설정의 plugins: ['react-hooks'] 같은 문자열 배열을 그대로 복사하면 flat config 형식이 아니므로 설정 오류가 나거나 설정이 로드되지 않을 수 있습니다.

React와 TypeScript 기준 수정 예시

React와 TypeScript를 같이 쓰는 프로젝트라면 검사 대상 파일 범위를 먼저 넓게 잡고, 플러그인을 객체로 등록하는지 확인합니다. TypeScript는 typescript-eslint의 recommended config를 기본으로 두고, 필요한 규칙을 뒤쪽 설정 객체에서 덧붙이는 구조가 관리하기 쉽습니다.

import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import reactHooks from 'eslint-plugin-react-hooks';
import tseslint from 'typescript-eslint';

export default defineConfig([
  {
    ignores: ['dist/**', 'build/**', 'coverage/**']
  },
  js.configs.recommended,
  tseslint.configs.recommended,
  {
    files: ['**/*.{js,jsx,ts,tsx}'],
    plugins: {
      'react-hooks': reactHooks
    },
    rules: {
      'no-console': 'warn',
      'react-hooks/rules-of-hooks': 'error',
      'react-hooks/exhaustive-deps': 'warn'
    }
  }
]);

이 예시에서 확인할 부분은 세 가지입니다. 제외 대상은 앞쪽에서 따로 분리했고, JavaScript와 TypeScript 추천 설정을 함께 사용했으며, React Hooks 플러그인은 import한 객체를 'react-hooks' namespace에 연결했습니다.

여기까지는 일반적인 문법 검사와 React Hooks 검사에 가깝습니다. @typescript-eslint/no-floating-promises처럼 타입 정보를 요구하는 규칙을 쓰려면 별도 typed linting 설정이 필요합니다. 이때는 parserOptions.projectService: true 또는 parserOptions.project 설정, 그리고 recommendedTypeChecked 같은 type-checked preset이나 규칙을 실제로 활성화했는지 함께 봐야 합니다.

빌드나 환경변수 문제와 함께 ESLint를 점검하는 경우라면 Vite 환경변수 import.meta.env undefined 오류 해결처럼 실행 환경을 먼저 확인해야 하는 글과 같이 보는 편이 좋습니다. ESLint 설정 오류와 런타임 환경변수 오류는 증상은 비슷해 보여도 확인 위치가 다릅니다.

실제 적용 여부 확인 순서

수정 후에는 에디터 화면만 보고 판단하지 않는 것이 좋습니다. VS Code의 ESLint 확장은 워크스페이스 상태나 서버 반영 시점 때문에 늦게 보일 수 있습니다. 터미널에서 특정 파일 하나를 지정해 ESLint가 계산한 최종 설정을 확인하는 방식이 더 정확합니다.

npx eslint --print-config src/App.tsx

--print-config 결과에서 원하는 규칙이 rules 안에 들어 있는지 확인합니다. 이 결과는 대상 파일 기준으로 계산된 최종 설정을 보여주므로, 목차처럼 원본 설정 객체를 그대로 보여주는 화면은 아닙니다. 적용 여부는 rules, plugins, languageOptions 쪽에서 확인합니다.

설정 파일 자체를 읽지 못하는지 의심된다면 debug 모드로 실행합니다.

npx eslint --debug src/App.tsx

debug 출력에서는 어떤 eslint.config.* 파일을 읽었는지 확인합니다. 모노레포, 예제 폴더, 기존 프로젝트를 복사한 구조에서는 생각한 루트와 실제 실행 루트가 다를 수 있습니다. ESLint가 다른 설정 파일을 읽고 있으면 현재 파일을 아무리 고쳐도 증상이 남습니다.

설정이 길어졌다면 Config Inspector도 확인 후보가 됩니다. 여러 플러그인과 shared config를 섞은 프로젝트에서는 어떤 설정 객체가 어느 파일에 적용되는지 시각적으로 확인하는 편이 빠를 때가 있습니다.

npx eslint --inspect-config

CI에서만 실패한다면 GitHub Actions npm ci lockfile Node 버전 오류 해결처럼 Node 버전과 lockfile 기준도 함께 봐야 합니다. 로컬에서는 최신 패키지가 깔렸는데 CI에서는 lockfile 기준으로 다른 ESLint 또는 plugin 버전이 설치될 수 있습니다.

다음에 같은 문제를 줄이는 기준

ESLint flat config 규칙 적용 안됨 문제를 해결하는 검증 순서

flat config로 옮길 때는 한 번에 모든 규칙을 복사하지 말고, 적용 범위를 먼저 작게 확인하는 편이 안정적입니다. 예를 들어 no-console처럼 결과를 바로 볼 수 있는 규칙 하나를 넣고 실제 컴포넌트 파일에서 잡히는지 본 뒤 React Hooks, TypeScript, import 정렬 같은 규칙을 붙이면 어디서 깨지는지 구분하기 쉽습니다.

  • eslint.config.js 또는 eslint.config.mjs가 실제 실행 루트에 있는지 확인합니다.
  • files는 실제 검사할 확장자와 하위 폴더를 포함하도록 작성합니다.
  • ignores는 전역 제외와 특정 범위 제외를 구분해서 작성합니다.
  • 플러그인은 문자열 배열이 아니라 import한 객체를 namespace에 연결합니다.
  • TypeScript 타입 기반 규칙은 typed linting 설정이 필요한지 따로 확인합니다.
  • 수정 후에는 --print-config로 대상 파일 기준 최종 설정을 확인합니다.

TypeScript 에러까지 같이 정리해야 한다면 TypeScript Property does not exist on type never 오류 해결처럼 타입 추론 문제를 분리해서 보는 것이 좋습니다. ESLint가 TypeScript 파일을 읽지 못하는 문제와 TypeScript 자체가 타입을 좁히지 못하는 문제는 해결 위치가 다릅니다.

마무리 점검

eslint.config.js로 바꾼 뒤 규칙이 적용되지 않는 문제는 대부분 규칙 이름보다 적용 대상 계산에서 생깁니다. 어떤 파일을 검사하는지, 그 파일에 어떤 설정 객체가 매칭되는지, 그 안에 플러그인과 TypeScript 설정이 제대로 연결되어 있는지를 순서대로 보면 원인을 줄일 수 있습니다.

다음에 같은 문제를 만났을 때는 설정 파일 전체를 다시 갈아엎기보다 대상 파일 하나를 정하고 --print-config부터 실행하는 것이 낫습니다. 최종 설정에 규칙이 없으면 files와 플러그인 등록을 보고, 규칙은 있는데 에디터에서만 안 보이면 ESLint 서버 재시작이나 워크스페이스 설정을 확인하면 됩니다.

공식 기준은 ESLint configuration files 문서, ESLint ignore 문서, ESLint debug 문서, typescript-eslint typed linting 문서를 함께 확인하면 좋습니다.

함께 확인하면 좋은 글

이 글이 마음에 드세요?

RSS 피드를 구독하세요!

댓글 남기기