Biome으로 포맷·린트·CI를 하나로 묶기

Biome을 프로젝트에 고정 설치하고 포맷·린트·import 정리를 같은 설정으로 실행하며 기존 ESLint·Prettier 환경에서 안전하게 이행하는 방법을 설명합니다.

Biome으로 포맷·린트·CI를 하나로 묶기

포맷터와 린터가 서로 다른 설정과 실행 명령을 가지면 로컬에서는 통과했는데 CI에서 실패하는 일이 잦아진다. Biome은 포맷, 린트, import 정리를 하나의 CLI와 설정 파일로 묶어 JavaScript·TypeScript 프로젝트의 검사 진입점을 단순하게 만든다. 기존 ESLint·Prettier 규칙을 모두 그대로 대체한다고 가정하지 말고 작은 범위에서 결과 차이를 확인하며 옮기는 것이 안전하다.

설치 전 확인

공식 문서는 프로젝트 안에 정확한 버전을 개발 의존성으로 고정하는 방식을 권장한다. 그러면 개발자 PC와 CI가 같은 바이너리를 사용한다. 아래 명령은 Node.js와 npm이 준비된 프로젝트를 전제로 한다.

npm install --save-dev --save-exact @biomejs/biome
npx @biomejs/biome --version

버전이 출력되면 설치가 끝난다. 전역 설치보다 프로젝트 설치를 먼저 권하는 이유는 사람마다 다른 버전이 자동으로 선택되는 문제를 줄이기 위해서다.

설정 파일 만들기

프로젝트 루트에서 초기 설정을 만든다.

npx @biomejs/biome init

생성된 biome.json을 버전 관리에 포함한다. 시작점은 다음처럼 단순하게 둘 수 있다.

{
  "$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2
  },
  "linter": {
    "enabled": true,
    "rules": { "recommended": true }
  },
  "javascript": {
    "formatter": { "quoteStyle": "single" }
  }
}

스키마 버전은 설치된 Biome 버전이 만든 초기 파일을 우선한다. 문서의 예시를 복사한 뒤 스키마 번호만 오래된 상태로 두지 않는다.

소스 코드가 Biome 검사를 거쳐 로컬 수정과 CI 검사로 나뉘는 흐름
소스 코드가 Biome 검사를 거쳐 로컬 수정과 CI 검사로 나뉘는 흐름

첫 검사를 돌리기

변경 없이 문제만 보고 싶다면 check를 사용한다.

npx @biomejs/biome check ./src

종료 코드가 0이면 설정 범위의 검사를 통과한 것이다. 진단이 출력되면 파일과 규칙을 읽고 수정 범위를 정한다. 안전 수정과 포맷을 적용할 때만 --write를 붙인다.

npx @biomejs/biome check --write ./src
git diff -- ./src

두 번째 git diff가 중요하다. 자동 수정 결과를 검토하지 않은 채 큰 코드베이스에 바로 커밋하지 않는다. 처음에는 한 디렉터리나 작은 패키지로 범위를 제한한다.

스크립트로 고정하기

팀원이 같은 명령을 쓰도록 package.json에 스크립트를 둔다.

{
  "scripts": {
    "format": "biome format --write .",
    "lint": "biome lint .",
    "check": "biome check .",
    "check:fix": "biome check --write .",
    "ci": "biome ci ."
  }
}

로컬에서는 npm run check:fix로 안전 수정을 적용하고, CI에서는 소스 파일을 바꾸지 않는 npm run ci를 사용한다. CI가 실패했는데 작업 트리가 자동으로 수정되는 구조는 원인 확인과 재현을 어렵게 한다.

제외 범위 정하기

빌드 산출물, 생성 코드, 외부에서 복사한 파일은 검사 대상에서 제외해야 할 수 있다. 현재 설치 버전의 설정 스키마를 기준으로 files와 VCS ignore 연동을 구성한다. .gitignore를 무조건 그대로 따를지, 생성 파일 중 일부는 검사할지 팀 정책을 먼저 정한다.

모노레포에서는 루트 설정 하나로 시작하되 패키지별 예외가 계속 늘어나면 하위 설정과 적용 범위를 분리한다. 규칙을 끄는 이유를 주석 가능한 biome.jsonc에 남기면 시간이 지나도 예외의 배경을 찾기 쉽다.

CI에 연결하기

의존성을 잠금 파일과 함께 설치하고 같은 스크립트를 실행한다. GitHub Actions의 최소 예시는 다음과 같다.

name: quality
on: [push, pull_request]

jobs:
  biome:
    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 ci

성공 기준은 워크플로 로그에서 Biome 단계가 종료 코드 0으로 끝나는 것이다. 로컬과 CI의 Node·패키지 잠금 파일·Biome 버전이 같아야 차이를 줄일 수 있다.

기존 도구와 이행

ESLint와 Prettier를 쓰던 프로젝트라면 하루에 모두 제거하지 않는다. 먼저 Biome을 추가해 진단과 포맷 차이를 비교한다. 공식 migrate 명령은 기존 설정을 가져오는 출발점이지만 모든 플러그인 규칙과 의미가 일대일로 대응하는 것은 아니다.

npx @biomejs/biome migrate prettier
npx @biomejs/biome migrate eslint
npx @biomejs/biome check ./src

마이그레이션 결과와 지원되지 않는 규칙을 검토한 뒤, 일정 기간 두 체계를 병행하거나 패키지별로 전환한다. 코드 의미를 바꿀 수 있는 unsafe 수정은 별도 브랜치에서 테스트와 리뷰를 거친다.

오류를 진단하기

에디터와 CLI 결과가 다르면 에디터 확장이 프로젝트의 로컬 바이너리와 루트 설정을 읽는지 확인한다. 설정이 예상대로 로드되지 않거나 데몬 문제가 의심되면 공식 진단 명령을 사용한다.

npx @biomejs/biome rage
npx @biomejs/biome check --help

파싱 오류가 발생하면 해당 언어·구문이 현재 Biome 버전에서 지원되는지 확인한다. 자동 생성 파일의 대량 오류는 규칙을 전부 끄기보다 검사 범위를 먼저 조정한다.

제거와 복구

시험 도입을 되돌릴 때는 패키지와 설정, package.json 스크립트, CI 단계를 함께 정리한다.

npm uninstall @biomejs/biome
rm -f biome.json biome.jsonc
git diff

기존 ESLint·Prettier 파일을 삭제했다면 버전 관리에서 복구하고 각 검사 명령을 다시 실행한다. 자동 수정 커밋을 별도로 두면 되돌리기도 쉽다.

출처