콘텐츠로 이동

ADR-0032: Frontend Linter & Formatter: Biome

Umbra 의 프론트엔드(apps/web)는 lint 와 format 을 단일 도구 Biome 으로 통합한다. ESLint + Prettier 조합은 사용하지 않는다.

Status

Accepted

  • Decided at — 2026-04-17
  • Decided by — Pablo

Context

apps/web 스캐폴딩 직전 시점에 lint/format 도구 선택을 확정해야 한다. frontend-conventions.md 는 "Biome 또는 ESLint + Prettier" 로 결정을 보류해 두었고, 스캐폴딩에서 패키지/설정 파일을 만들기 전에 이 결정을 잠근다.

요구사항:

  • TypeScript + React 19 + TanStack 생태계 지원
  • Tailwind class 정렬 자동화
  • IDE (VSCode, JetBrains) 통합
  • CI 에서 빠른 실행 (PR feedback loop 단축)
  • 설정 파일 수 최소화

Decision

apps/web 의 lint 와 format 을 Biome 단일 도구로 처리한다.

  • apps/web/biome.json — 단일 설정 파일 (lint + format + import sort)
  • bun --cwd apps/web run lint → 내부적으로 biome check
  • bun --cwd apps/web run format → 내부적으로 biome format --write
  • Tailwind class 정렬은 Biome 의 nursery/useSortedClasses rule 사용
  • ESLint, Prettier, prettier-plugin-tailwindcss 는 도입하지 않음

apps/web/package.json 의 devDependencies 는 @biomejs/biome 만 추가한다. 향후 Biome 가 미지원하는 React 전용 rule 이 필요해지면 ESLint 추가가 아니라 Biome plugin 또는 custom rule 로 해결한다.

Consequences

Positive

  • 빠른 실행 — Biome 는 Rust 기반으로 ESLint+Prettier 조합 대비 ~10배 빠르다. CI 시간 단축
  • 단일 설정 파일eslint.config.js, .prettierrc, prettier.config.js, .eslintignore, .prettierignore 다섯 파일이 biome.json 하나로 통합
  • devDependencies 축소 — 평균 6~10개 패키지 (eslint, @typescript-eslint/*, prettier, prettier-plugin-tailwindcss, eslint-plugin-react-hooks 등) → 1개
  • 포맷/린트 충돌 없음 — 단일 도구라 rule 간 모순 발생 불가
  • IDE 응답성 개선 — Language Server 부팅이 빠름

Negative

  • 생태계 성숙도 차이 — ESLint 의 plugin 생태계 (수천 개) 대비 Biome plugin 은 제한적. 특정 React 패턴 lint 가 누락될 수 있음
  • Tailwind plugin 의 v4 대응 — Biome 의 useSortedClasses 가 Tailwind v4 (CSS-first config) 의 모든 케이스를 다 다루지 못할 수 있음. 필요 시 IDE format-on-save 보조
  • 레퍼런스 자료 차이 — React 커뮤니티 튜토리얼이 ESLint 가정인 경우가 많음

Neutral

  • 설정 마이그레이션 비용은 0 (스캐폴딩 전 결정이므로)
  • Biome v2 가 stable. v1 에서 v2 로의 호환성 이슈는 이미 정리됨

Alternatives considered

Alternative 1: ESLint + Prettier + plugins

Pros

  • 업계 표준, 거의 모든 React 프로젝트의 기본 선택
  • plugin 생태계가 매우 풍부 (eslint-plugin-react-hooks, eslint-plugin-jsx-a11y, @typescript-eslint/* 등)
  • 커스텀 rule 작성 자료 많음

Cons

  • 설정 파일 분산 (eslint, prettier, ignore 파일들)
  • devDependencies 많음 (보통 10개 이상)
  • 두 도구가 format 영역에서 겹치므로 eslint-config-prettier 같은 충돌 회피 패키지 필수
  • 실행 속도 느림 (특히 monorepo 에서 누적)

Why rejected — Umbra 의 apps/web 규모(MVP 한 개 SPA)에서 ESLint 의 plugin 다양성 이점이 작고, 설정 단순성과 실행 속도의 이점이 더 크다. 후일 특정 rule 이 절실해지면 Biome 위에 ESLint 를 보조 도구로 추가하는 방식도 가능 (현 시점엔 불필요).

Alternative 2: Rome (Biome 의 전신)

Pros

  • 동일한 단일 도구 컨셉

Cons

  • 프로젝트 자체가 archive (Biome 가 fork 후 활발히 개발 중)

Why rejected — Rome 은 더 이상 유지보수되지 않음. Biome 가 사실상의 후속 프로젝트.

Alternative 3: dprint

Pros

  • 빠른 format 도구
  • plugin 시스템

Cons

  • format 만 다루고 lint 는 별도 도구 필요 → 단일 도구 목적과 어긋남

Why rejected — Biome 가 lint + format 통합이라는 결정 기준에 더 부합.

Compliance

  • apps/web/biome.json 은 commit 되며 root 컨벤션과 일치해야 함
  • CI 의 lint-web job 은 bunx biome ci . 또는 bun --cwd apps/web run lint 사용
  • PR 에서 lint 실패 시 merge 차단
  • ESLint / Prettier 관련 패키지가 apps/web/package.json 에 추가되면 review 단계에서 차단
  • IDE 설정 권장 사항은 frontend-conventions.md 에 명시

Revisit triggers

  • Biome 가 1년 이상 stable release 없이 정체되면 ESLint+Prettier 로 회귀 검토
  • 팀이 4명 이상으로 확장되며 React 전용 lint rule 다수 도입이 필요해지면 ESLint 보조 도입 검토
  • Tailwind v4 의 class 정렬을 Biome 가 끝내 지원 못 하면 prettier-plugin-tailwindcss 만 부분 도입

References

  • ADR-0008 — Frontend runtime (Bun + Vite + React)
  • ADR-0009 — Monorepo: Bun workspace (single go.mod)
  • ADR-0029 — UI Library: shadcn/ui