새로운 Next.js 프로젝트를 설치하고 린트 적용 중에 발생한 에러:
Oops! Something went wrong! :(
ESLint: 9.39.1
TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
기존 나의 eslint.config.mjs:
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
import unusedImports from "eslint-plugin-unused-imports";
import tseslint from "typescript-eslint";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
// 1) Next 기본 권장 규칙
...compat.extends("next/core-web-vitals", "next/typescript"),
// 2) 전역 ignore
{
ignores: [
"node_modules/**",
...
Next.js cli로 설치하면 자동으로 생성되는 eslint.config.mjs에다가 내가 필요한 린트 설정을 추가한 상황이었다.
이와 관련된 이슈 토론: https://github.com/eslint/eslint/issues/20237
Bug: Converting circular structure to JSON when showing config error · Issue #20237 · eslint/eslint
Environment Node version: v24.7.0 npm version: 11.6.1 Local ESLint version: 9.36.0 Global ESLint version: none Operating System: Fedora 42 GNU/Linux What parser are you using? Default (Espree) What...
github.com
Next.js 공식문서의 ESLint 설명: https://nextjs.org/docs/app/api-reference/config/eslint
Configuration: ESLint | Next.js
Learn how to use and configure the ESLint plugin to catch common issues and problems in a Next.js application.
nextjs.org
Next.js는 애플리케이션에서 흔히 발생하는 문제를 쉽게 포착할 수 있도록 eslint-config-next 라는 ESLint 설정 패키지를 제공합니다. 이 패키지에는 @next/eslint-plugin-next 플러그인과 eslint-plugin-react, eslint-plugin-react-hooks 에서 권장하는 규칙 세트가 포함되어 있습니다.
또한, 이 패키지는 주로 세 가지 구성을 제공한다고 한다:
| 구성 | 설명 |
| eslint-config-next | Next.js, React, React Hooks 규칙이 포함된 기본 구성입니다. JavaScript 및 TypeScript 파일을 모두 지원합니다. |
| eslint-config-next/core-web-vitals | 기본 구성의 모든 것을 포함하며, Core Web Vitals에 영향을 미치는 규칙을 경고(warnings)에서 오류(errors)로 상향 조정합니다. 대부분의 프로젝트에 권장됩니다. |
| eslint-config-next/typescript | TypeScript 프로젝트를 위해 typescript-eslint에서 제공하는 TypeScript 관련 린팅 규칙을 추가합니다. 기본 또는 core-web-vitals 구성과 함께 사용하세요. |
그래서 나는 eslint-config-next에서 포함하는 패키지들이 궁금했다.
npm info eslint-config-next dependencies
위 명령어를 통해 eslint-config-next가 포함하는 패키지를 확인할 수 있었다:
{
globals: '16.4.0',
'typescript-eslint': '^8.46.0',
'eslint-plugin-react': '^7.37.0',
'eslint-plugin-import': '^2.32.0',
'eslint-plugin-jsx-a11y': '^6.10.0',
'@next/eslint-plugin-next': '16.0.10',
'eslint-plugin-react-hooks': '^7.0.0',
'eslint-import-resolver-node': '^0.3.6',
'eslint-import-resolver-typescript': '^3.5.2'
}
그에 따라, 세팅 초반에 내가 eslint 설정하면서 설치했던 eslint-plugin-import나, eslint-import-resolver-typescript 같은 패키지가 불필요해져서 삭제하였다.
다시 Next 공식 문서 내용으로 돌아와서,
eslint.config.mjs 세팅을 다음과 같이 하라는 내용이 있었다. 이를 참고하여 나의 에러를 해결할 수 있었다.
import { defineConfig, globalIgnores } from 'eslint/config'
import nextVitals from 'eslint-config-next/core-web-vitals'
const eslintConfig = defineConfig([
...nextVitals,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
])
export default eslintConfig
복잡하게 FlatCompat을 사용하지 않고, eslint-config-next에서 nextVitals를 import 하여 Flat Config 형식으로 적용한 것을 볼 수 있다. 또한, defineConfig와 globalIgnores를 사용하고 있다.
그에 따라 나의 eslint.config.mjs도 다음과 같이 수정하여 문제를 해결하였다:
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
import tseslint from "typescript-eslint";
import unusedImports from "eslint-plugin-unused-imports";
const eslintConfig = defineConfig([
// 1) Next 기본 권장 규칙
...nextVitals,
...nextTs,
// 2) 전역 ignore
globalIgnores([
"node_modules/**",
정리하면,
github 이슈 토론에서도 언급 됐듯이 Next.js의 공식 린팅 설정 패키지인 eslint-config-next의 최신 버전이 Flat Config를 지원하도록 업데이트되었기 때문에, 레거시 설정을 변환하는 FlatCompat을 사용할 필요가 없어졌다. eslint-config-next에서 nextVitals와 nextTs를 직접 import하여 순환 참조를 유발했던 레거시 설정 변환 과정 자체가 생략되었고, 결과적으로 충돌이 해결되었다.
문제가 발생했던 이유를 Gemini의 도움으로 정리하면:
- 원인 1: 순환 참조 객체 생성 (FlatCompat의 부작용) FlatCompat을 통해 Next.js 레거시 설정(extends("next/..."))을 Flat Config로 변환하는 과정에서, 특히 React와 같은 내부 플러그인 객체들이 순환 참조(Circular Reference)를 포함하는 복잡한 구성 객체를 생성했습니다.
- 원인 2: ESLint의 오류 처리 버그 (충돌의 직접적인 이유) 구성 파일에 유효성 검사 오류가 감지되었을 때, ESLint는 오류 보고를 위해 이 순환 참조 객체를 JSON.stringify()를 이용해 문자열화하려 했고, 이 과정에서 TypeError: Converting circular structure to JSON 오류가 발생하며 ESLint 프로세스 자체가 충돌했습니다.
(참고로 FlatCompat은 .eslintrc나 .eslintrc.js 등과 같은 레거시 설정을 ESLint 9의 Flat Config 형식으로 변환하는 래퍼 역할을 한다.)
'TIL*' 카테고리의 다른 글
| 웹뷰를 이용해 웹 서비스를 앱으로 빠르게 구현하기 | 인프콘2023 (0) | 2025.12.08 |
|---|---|
| Mac 시스템 데이터 정리하기 (0) | 2025.12.05 |
| AI의 버그 찾기(서버 로그 vs 브라우저 로그) (0) | 2025.12.03 |
| TypeScript Discriminated Union(구별된 유니온) 패턴 적용하기 (0) | 2025.11.19 |
| Vite를 사용하는 이유, Vite Public 디렉토리 선택 기준 (0) | 2025.11.17 |