ESLint vs Biome vs Oxlint — 2026년 프론트엔드 린팅 도구의 속도·생태계·마이그레이션 비용 비교
린터(linter)는 코드를 실행하기 전에 잠재적 버그, 나쁜 패턴, 스타일 불일치를 잡아주는 도구입니다. CI 파이프라인에서 린팅이 없으면 리뷰에서 걸렸을 실수들이 프로덕션까지 가는 경험, 한 번쯤 해보셨을 겁니다.
솔직히 저도 "ESLint면 충분하지"라고 생각하며 꽤 오랫동안 지내왔습니다. 그러다 올해 모노레포(monorepo, 여러 패키지를 단일 저장소에서 관리하는 구조) CI에서 ESLint가 60초 넘게 돌아가는 걸 보면서 처음으로 진지하게 대안을 찾기 시작했는데, 생태계가 생각보다 많이 바뀌어 있었습니다. ESLint v10이 나오면서 구형 설정 방식이 완전히 사라졌고, Rust로 만들어진 Biome과 Oxlint가 대형 코드베이스에서 수십 초를 수 초로 줄이는 걸 직접 확인했거든요.
이 글은 2026년 현재 세 도구 — ESLint, Biome, Oxlint — 의 속도·생태계·마이그레이션 비용을 실제 상황에 맞게 비교하고, 프로젝트 상황에 따른 선택 기준을 잡는 것을 목표로 합니다. 신규 프로젝트인지, 레거시 플러그인이 많은지, CI 속도가 병목인지 — 이 글을 읽고 나면 자신의 상황에 맞는 하나를 고를 수 있습니다.
핵심 개념
2026년 린팅 생태계 지형도
먼저 세 도구의 포지션을 한눈에 정리해봤습니다.
| 항목 | ESLint | Biome | Oxlint |
|---|---|---|---|
| 구현 언어 | JavaScript (Node.js) | Rust | Rust |
| 역할 | 린터 | 린터 + 포매터 | 린터 (포매터는 Oxfmt 별도) |
| 상대 속도 | 기준 (1×) | 약 15–20배 빠름 | 약 50–100배 빠름 |
| 내장 규칙 수 | 수백 개 + 무한 플러그인 | 500개+ (v2.5) | 700개+ |
| 설정 복잡도 | 높음 | 매우 낮음 | 낮음 |
| 플러그인 생태계 | 업계 최고 수준 | 초기 단계 (GritQL) | JS 플러그인 알파 단계 |
| 최신 안정 버전 | v10 (2026년 2월) | v2.5 (2026년 6월) | v1.0 (2025년 8월) |
속도 수치는 100k LOC(약 10만 줄 규모) 코드베이스, M1 Pro 기준 벤치마크를 참고한 값입니다. 활성화된 규칙 수와 프로젝트 구조에 따라 실제 차이는 달라질 수 있습니다.
ESLint v10이 가져온 변화
ESLint는 2013년부터 쌓아온 압도적인 생태계를 가진 도구입니다. 주당 1억 3천만 npm 다운로드라는 숫자가 현재의 의존도를 잘 보여줍니다.
v10에서 가장 큰 변화는 구형 .eslintrc 설정 방식이 완전히 제거된 것입니다. v9에서 flat config(eslint.config.js)가 기본으로 전환됐고, v10에서는 되돌아갈 방법이 없어졌습니다.
Flat config란? 기존의
.eslintrc.json,.eslintrc.js등 여러 파일로 분산되던 설정을eslint.config.js단일 파일로 일원화한 방식입니다. 디렉토리 계층을 따라 올라가며 설정을 병합하던 방식과 달리, 파일 하나에서 모든 설정을 명시적으로 제어합니다.
문제는 eslint-plugin-react, eslint-config-next 같은 주요 플러그인들의 flat config 대응 속도가 저마다 다르다는 점입니다. v10으로 업그레이드하자마자 설치 충돌이 발생하는 사례가 이슈 트래커에 줄을 잇고 있고, ESLint v9.x는 2026년 8월 EOL이 예정되어 있어 생태계 전체에 마이그레이션 압박이 형성된 상황입니다.
Biome — 린터와 포매터를 하나로
Biome은 원래 Rome이라는 이름의 프로젝트에서 시작했습니다. 핵심 아이디어는 린터와 포매터를 단일 바이너리에 통합하는 것으로, 설정 파일 하나(biome.json)로 린팅과 포매팅을 동시에 처리합니다.
ESLint와 Prettier를 각각 설정하고 서로 충돌하지 않게 유지하는 번거로움을 겪어보셨다면, 이 접근이 왜 매력적인지 바로 이해가 되실 겁니다.
2025년 말 v2.0 "Biotype" 출시 이후 매우 빠른 릴리스 사이클을 이어가고 있습니다. v2.5에서는 500개 규칙 달성, 크로스 파일 린팅(CSS 클래스 미사용 탐지 등), --watch 모드가 한꺼번에 추가됐습니다.
자체 플러그인 시스템으로 GritQL을 채택했는데, JavaScript/TypeScript 코드 패턴을 쿼리 언어처럼 표현해 커스텀 린트 규칙을 작성하는 방식입니다. ESLint의 AST(Abstract Syntax Tree) 기반 플러그인이 JavaScript로 직접 트리를 순회하며 규칙을 구현하는 것과 달리, GritQL은 패턴 매칭 문법으로 더 선언적으로 접근합니다. 개념 자체는 흥미롭지만, ESLint 플러그인 생태계처럼 수천 개의 검증된 패키지가 즉시 쓸 수 있는 단계와는 아직 거리가 있습니다.
Oxlint — 속도에 집중한 선택
Oxlint는 Vercel이 주도하는 OXC(The JavaScript Oxidation Compiler) 프로젝트의 린터 컴포넌트입니다. Vite 핵심 팀과도 밀접하게 연관되어 있습니다. 2025년 8월 v1.0 안정 버전을 출시했고, Shopify, Airbnb, Mercedes-Benz 같은 대기업이 프로덕션에 도입했습니다.
700개 이상의 내장 규칙과 TypeScript 타입 인식(type-aware) 린팅이 특징입니다.
타입 인식 린팅이란? 일반 린팅은 코드의 문법 구조(AST)만 분석하지만, 타입 인식 린팅은 TypeScript의 타입 정보까지 활용해 더 정밀한 규칙을 적용합니다. 예를 들어
.then()을 Promise가 아닌 값에 호출하는 버그를 잡거나, async 함수 반환값이 의도치 않게 무시되는 패턴을 검출할 수 있습니다.@typescript-eslint의 타입 인식 규칙은 총 61개인데, Oxlint는 이 중 59개를 이미 지원합니다.
2026년 3월에는 JavaScript 플러그인 API 알파를 공개해 ESLint 플러그인 생태계와의 호환성 간극을 좁히고 있습니다.
실전 적용
예시 1: ESLint flat config — 플러그인 의존도가 높은 기존 프로젝트
Next.js, NestJS, Storybook 등 프레임워크 공식 ESLint 플러그인을 사용 중인 프로젝트라면, 솔직히 지금 당장은 ESLint 외에 현실적인 대안이 없습니다. @typescript-eslint/eslint-plugin이 주당 1억 600만 다운로드를 기록한다는 수치가 의존도를 잘 보여줍니다.
ESLint v9+/v10 환경에서의 flat config 설정 예시입니다.
// eslint.config.js (flat config, ESLint v9+/v10)
import tsPlugin from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
export default [
{
ignores: ['dist/**', 'node_modules/**', '**/*.d.ts'], // .eslintignore 파일 대신 여기서 지정
files: ['**/*.ts', '**/*.tsx'],
languageOptions: { parser: tsParser },
plugins: { '@typescript-eslint': tsPlugin },
rules: {
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
},
];| 구성 요소 | 설명 |
|---|---|
ignores |
기존 .eslintignore 파일을 대체합니다. flat config에서는 이 배열에 직접 패턴을 지정합니다 |
files |
이 설정이 적용될 파일 패턴을 지정합니다 |
languageOptions.parser |
TypeScript 파싱을 위한 파서를 지정합니다 |
plugins |
플러그인 객체를 직접 import해서 등록합니다. 구형 방식의 문자열 기반 등록과 다릅니다 |
예시 2: Biome — 신규 프로젝트, 린터·포매터 통합 설정
설정 파일을 거의 만질 필요가 없다는 게 Biome의 가장 큰 강점입니다. biome.json 하나로 린팅과 포매팅을 모두 처리합니다.
{
"$schema": "https://biomejs.dev/schemas/2.5.0/schema.json",
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedVariables": "error"
},
"css": {
"noUnusedClasses": "error"
}
}
},
"formatter": {
"indentStyle": "space",
"indentWidth": 2
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"trailingCommas": "all"
}
}
}# 린팅 + 포매팅을 한 번에 검사하고 자동 수정
npx @biomejs/biome check --write .
# 파일 변경 감지 모드 (개발 중 실시간 검사)
npx @biomejs/biome check --watch .
# 기존 .eslintrc + .prettierrc를 자동으로 biome.json으로 변환
npx @biomejs/biome migrate eslint
npx @biomejs/biome migrate prettierv2.5에서 추가된 크로스 파일 린팅(noUnusedClasses)은 CSS 파일에 정의된 클래스가 JSX나 HTML에서 실제로 사용되는지 파일 경계를 넘어 추적합니다. 기존 린팅이 파일 하나씩 독립적으로 분석했다면, 이제 파일 간 관계를 이해하는 단계로 진화했다는 의미입니다.
기존 ESLint 규칙의 80–90%가 Biome 규칙으로 직접 대응됩니다. 나머지 10–20%는 수동으로 처리하거나 포기해야 할 수 있는데, 프레임워크 전용 규칙(Next.js의 @next/next 플러그인 규칙 등)이 여기에 해당합니다.
예시 3: Oxlint — CI 속도 병목 해소, ESLint 병렬 실행 전략
100k LOC 규모의 모노레포에서 ESLint가 45–90초 걸리는 작업을 Oxlint는 2초 이내에 처리합니다. 저도 처음엔 "설정도 거의 없는데 얼마나 잘 되겠어"라고 생각했는데, 직접 병렬 실행해보고 나서 생각이 완전히 바뀌었습니다.
# 설치
pnpm add -D oxlint
# 단독 실행
npx oxlint .
# TypeScript 타입 인식 린팅 활성화
npx oxlint --tsconfig tsconfig.json .// package.json — ESLint와 병렬 실행하는 하이브리드 전략
{
"scripts": {
"lint": "oxlint . && eslint .",
"lint:fast": "oxlint ."
}
}하이브리드 전략이란 Oxlint가 커버하는 700개+ 규칙은 ESLint에서 비활성화하고, 커스텀 플러그인이나 프레임워크 전용 규칙만 ESLint가 처리하도록 역할을 나누는 방식입니다. 완전 마이그레이션 없이도 CI 속도를 크게 단축할 수 있습니다.
JS 플러그인 알파를 활용하면 ESLint 호환 플러그인을 Oxlint에서 직접 사용할 수도 있습니다.
// oxlint.config.js (알파 — 2026년 3월 공개)
export default {
plugins: ['./my-custom-plugin.js'],
rules: {
'my-plugin/my-rule': 'error',
},
};같은 규칙을 세 도구에서 설정하면
"미사용 변수 감지"라는 동일한 규칙을 세 도구에서 어떻게 설정하는지 나란히 보면 차이가 바로 보입니다.
// ESLint — eslint.config.js
rules: {
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
}// Biome — biome.json (규칙 이름과 구조가 다릅니다)
{
"linter": {
"rules": {
"correctness": {
"noUnusedVariables": "error"
}
}
}
}// Oxlint — oxlint.json (ESLint 호환 이름 그대로 사용합니다)
{
"rules": {
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }]
}
}Biome은 규칙 이름이 ESLint와 다르고 correctness, style 같은 카테고리로 묶이는 구조입니다. Oxlint는 ESLint와 동일한 규칙 이름을 유지해 마이그레이션 허들이 낮습니다. 기존 ESLint 설정을 옮겨올 때 체감 차이가 꽤 납니다.
장단점 분석
도구별 장단점 한눈에 보기
| 도구 | 장점 | 단점 | 대응 방안 |
|---|---|---|---|
| ESLint | 업계 최고의 플러그인 생태계 (React, Vue, TypeScript, Jest, Storybook 등 모두 지원) | 대형 프로젝트에서 심각한 속도 병목 (100k LOC 기준 45–90초) | Oxlint 병렬 실행으로 부하 분산 |
| ESLint | 타입 인식 린팅(@typescript-eslint) 성숙도 최고 수준 |
v10 마이그레이션 시 플러그인 flat config 호환성 충돌 빈번 | 업그레이드 전 각 플러그인의 v10 지원 여부 먼저 확인 |
| ESLint | 커스텀 규칙 작성이 자유롭고 문서·커뮤니티 자원 풍부 | 포매팅은 Prettier를 별도로 구성해야 함 | — |
| Biome | 린터 + 포매터를 하나의 바이너리·설정 파일로 관리 | ESLint 플러그인 생태계 미지원 (GritQL은 초기 단계) | 프레임워크 전용 규칙이 필요한 프로젝트에는 부적합 |
| Biome | ESLint 대비 15–20배 빠른 속도, VS Code·JetBrains·Zed LSP(에디터 자동완성·오류 표시 통합) 지원 우수 | 기존 프로젝트 마이그레이션 시 10–20% 규칙 수동 처리 필요 | biome migrate eslint로 자동 변환 후 수동 보완 |
| Biome | 설정 없이 biome check .만으로 즉시 실행 가능 |
TypeScript 타입 인식 규칙 일부 제한 | — |
| Oxlint | ESLint 대비 50–100배 빠른 속도 (100k LOC 기준 90초 → 2초) | JS 플러그인 지원이 아직 알파 단계 | 복잡한 커스텀 플러그인은 ESLint 병렬 실행으로 처리 |
| Oxlint | ESLint와 병렬 실행하는 단계적 마이그레이션 전략 지원 | 단독 린터로 포매팅은 Oxfmt 또는 Prettier 별도 필요 | — |
| Oxlint | v1.0 안정화 완료, Shopify·Airbnb·Mercedes-Benz 프로덕션 검증 | oxlint.config.ts 동적 설정 파일 지원 미완성 |
현재는 정적 설정 방식으로 대응 |
실무에서 자주 마주치는 실수
-
ESLint v10으로 올리기 전에 플러그인 호환성을 확인하지 않는 경우입니다. 특히
eslint-config-next,@typescript-eslint버전이 맞지 않으면 설치 자체가 실패합니다. 저도 한 번 별 생각 없이pnpm update돌렸다가 CI가 통째로 터진 적이 있었습니다. 업그레이드 전 각 플러그인의 GitHub 이슈나 CHANGELOG에서 v10 지원 선언 여부를 먼저 확인하는 것을 권장합니다. -
Biome을 레거시 플러그인이 많은 프로젝트에 바로 밀어 넣으면 공백이 생깁니다.
eslint-plugin-react-hooks,eslint-plugin-jsx-a11y같은 플러그인을 Biome이 대체할 수 없거든요. 실제로 팀 프로젝트에 Biome을 붙여봤을 때, 접근성 규칙 공백이 생겨서 결국 하이브리드 구성으로 타협했습니다. 신규 프로젝트나 플러그인 의존성이 적은 프로젝트에 먼저 적용해보는 것이 현실적입니다. -
Oxlint를 "ESLint 완전 대체재"로 접근하면 예상보다 빨리 한계에 부딪힙니다. 현시점에서 JS 플러그인 지원은 알파 단계입니다. "완전 교체"보다는 "ESLint 위에 Oxlint를 추가해 속도를 높이는" 하이브리드 전략이 훨씬 안정적입니다.
마치며
2026년 현재 선택지는 꽤 명확하게 갈립니다.
- 레거시 플러그인이 많다면 → ESLint (현재로선 대안이 없습니다)
- 신규 프로젝트를 시작한다면 → Biome (설정 없이 바로 시작, 린터·포매터 일체형)
- CI 속도가 급한 기존 팀이라면 → Oxlint 병렬 실행 (설정 몇 줄로 수십 초 절감)
저는 개인 사이드 프로젝트는 Biome으로 완전 전환했고, 팀 프로젝트에서는 Oxlint 하이브리드를 실험 중입니다. CI 시간이 60초에서 5초로 줄어든 것만으로도 충분히 가치 있었습니다.
지금 바로 시작해볼 수 있는 3단계:
-
현재 프로젝트에 Oxlint를 추가해볼 수 있습니다.
pnpm add -D oxlint로 설치하고npx oxlint .을 실행해보시면, 기존 ESLint 설정을 건드리지 않고도 속도 차이를 바로 체감할 수 있습니다. -
ESLint v10 마이그레이션이 필요한 팀이라면,
npx @eslint/config-inspector로 현재 설정을 시각화하고 각 플러그인의 flat config 지원 여부를 확인한 다음 업그레이드 순서를 잡아보시는 것을 권장합니다. v9.x EOL(2026년 8월)이 다가오고 있으니 지금 시작하시면 여유 있게 전환할 수 있습니다. -
신규 프로젝트를 시작한다면
npx @biomejs/biome init으로 Biome 설정을 만들고,.eslintrc와.prettierrc없이biome.json하나로 린팅·포매팅을 모두 처리해보시면 좋습니다. 한 번 익숙해지면 두 도구를 따로 관리하던 시절로 돌아가기 어려울 수 있습니다.
참고 자료
- Biome vs ESLint vs Oxlint 2026: Which JS Linter to Pick | PkgPulse
- OXC vs ESLint vs Biome: JavaScript Linting in 2026 | PkgPulse
- Biome vs Oxlint in 2026: Which Rust-Powered Linter Should You Replace ESLint With | jsmanifest
- Biome v2.5 — 500 Lint Rules, Plugin Code Fix, and Cross-File Linting | Biome 공식 블로그
- Biome v2 — Biotype 공식 발표 | Biome 공식 블로그
- Biome Roadmap 2026 | Biome 공식 블로그
- Announcing Oxlint 1.0 | VoidZero
- Oxlint Benchmarks | oxc.rs 공식
- ESLint v10.0.0 Released | ESLint 공식 블로그
- ESLint v9.0.0 Retrospective | ESLint 공식 블로그
- Speed kills: It's time to retire ESLint and migrate to Oxlint | LogRocket
- Migrating from ESLint, Biome, and Prettier to Oxlint and Oxfmt | Nicolas Charpentier
- Biome: The ESLint and Prettier Killer? Migration Guide 2026 | DEV Community
- TypeScript Linting and Formatting Tools Compared | sph.sh
- Oxlint Alpha Adds ESLint Plugin Support | Prism News
- Type-Aware Linting | Oxlint 공식 문서
- Biome vs ESLint: Comparing JavaScript Linters and Formatters | Better Stack