Biome 2.0 Chega - Toolchain Ultra-Rápido que Substitui ESLint/Prettier

2025.12.02

O Biome é um toolchain JavaScript/TypeScript ultra-rápido feito em Rust. Integra as funcionalidades do ESLint e Prettier em uma única ferramenta, melhorando a experiência de desenvolvimento com velocidade avassaladora. Em 2025, com o lançamento do Biome 2.0, a adoção em mais projetos está avançando.

O que é o Biome

Comparação de Toolchains

flowchart TB
    subgraph Traditional["Configuração Tradicional"]
        Workflow1["Fluxo de Desenvolvimento"]
        ESLint["ESLint<br/>(JavaScript)"]
        Prettier["Prettier<br/>(JavaScript)"]
        TSC["TypeScript<br/>tsc"]
        Config1["Múltiplos arquivos de configuração necessários<br/>(.eslintrc, .prettierrc, tsconfig.json)"]

        Workflow1 --> ESLint
        Workflow1 --> Prettier
        Workflow1 --> TSC
        ESLint --> Config1
        Prettier --> Config1
        TSC --> Config1
    end
flowchart TB
    subgraph BiomeArch["Configuração com Biome"]
        Workflow2["Fluxo de Desenvolvimento"]
        Biome["Biome (Rust)<br/>✓ Linter<br/>✓ Formatter<br/>✓ Import Sort"]
        Config2["Gerenciado com 1 arquivo biome.json"]

        Workflow2 --> Biome --> Config2
    end

Comparação de Desempenho

FerramentaProcessamento de 1000 arquivosUso de Memória
ESLint + PrettierCerca de 30 segundos~500MB
BiomeCerca de 0,5 segundos~50MB

Cerca de 60x mais rápido, 1/10 da memória

Instalação e Configuração

Instalação Básica

# npm
npm install --save-dev --save-exact @biomejs/biome

# pnpm
pnpm add --save-dev --save-exact @biomejs/biome

# yarn
yarn add --dev --exact @biomejs/biome

# bun
bun add --dev --exact @biomejs/biome

# Inicialização do arquivo de configuração
npx @biomejs/biome init

Arquivo de Configuração Básico

// biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "semicolons": "always"
    }
  }
}

Configuração de Scripts no package.json

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

Configuração Detalhada

Exemplo de Configuração Completa

{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "files": {
    "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.js", "src/**/*.jsx"],
    "ignore": [
      "node_modules",
      "dist",
      "build",
      ".next",
      "coverage",
      "*.min.js"
    ]
  },
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "complexity": {
        "noExcessiveCognitiveComplexity": {
          "level": "warn",
          "options": {
            "maxAllowedComplexity": 15
          }
        },
        "noForEach": "warn"
      },
      "correctness": {
        "noUnusedVariables": "error",
        "noUnusedImports": "error",
        "useExhaustiveDependencies": "warn"
      },
      "performance": {
        "noAccumulatingSpread": "warn",
        "noDelete": "warn"
      },
      "security": {
        "noDangerouslySetInnerHtml": "error"
      },
      "style": {
        "noNonNullAssertion": "warn",
        "useConst": "error",
        "useTemplate": "error",
        "noParameterAssign": "error"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "warn",
        "noDebugger": "error"
      },
      "nursery": {
        "useSortedClasses": {
          "level": "warn",
          "options": {
            "attributes": ["className", "class"],
            "functions": ["clsx", "cn", "cva"]
          }
        }
      }
    }
  },
  "formatter": {
    "enabled": true,
    "formatWithErrors": false,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf",
    "lineWidth": 100,
    "attributePosition": "auto"
  },
  "javascript": {
    "formatter": {
      "enabled": true,
      "quoteStyle": "single",
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSpacing": true,
      "bracketSameLine": false
    },
    "parser": {
      "unsafeParameterDecoratorsEnabled": true
    }
  },
  "json": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100
    }
  },
  "css": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineWidth": 100,
      "quoteStyle": "double"
    },
    "linter": {
      "enabled": true
    }
  },
  "overrides": [
    {
      "include": ["*.test.ts", "*.test.tsx", "*.spec.ts"],
      "linter": {
        "rules": {
          "suspicious": {
            "noExplicitAny": "off"
          }
        }
      }
    },
    {
      "include": ["*.config.js", "*.config.ts"],
      "linter": {
        "rules": {
          "style": {
            "noDefaultExport": "off"
          }
        }
      }
    }
  ]
}

Categorias de Regras do Linter

Lista de Categorias de Regras

CategoriaExemplo de RegraDescrição
a11y (Acessibilidade)useAltTextExige atributo alt em imagens
useKeyWithClickEventsOperação por teclado em eventos de clique
complexity (Complexidade)noBannedTypesDetecta uso de tipos proibidos
noForEachRecomenda for…of em vez de forEach
noExcessiveCognitiveComplexityLimite de complexidade cognitiva
correctness (Correção)noUnusedVariablesDetecta variáveis não utilizadas
noUnusedImportsDetecta imports não utilizados
useExhaustiveDependenciesArray de dependências do useEffect
performance (Desempenho)noAccumulatingSpreadProíbe acumulação de operadores spread
noDeleteAlerta sobre uso do operador delete
security (Segurança)noDangerouslySetInnerHtmlDetecta vulnerabilidades XSS
noGlobalEvalProíbe uso de eval()
style (Estilo)useConstUsar const para variáveis não reatribuídas
useTemplateTemplate literals em vez de concatenação
noParameterAssignProíbe reatribuição de parâmetros
suspicious (Código Suspeito)noExplicitAnyAlerta sobre uso do tipo any
noConsoleLogAlerta sobre uso de console.log
noDebuggerProíbe declarações debugger

Exemplo de Configuração Detalhada de Regras

{
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": {
          "level": "warn",
          "options": {
            "hooks": [
              {
                "name": "useQuery",
                "stableResult": [1]
              },
              {
                "name": "useMutation",
                "stableResult": [1]
              },
              {
                "name": "useCustomHook",
                "closureIndex": 0,
                "dependenciesIndex": 1
              }
            ]
          }
        }
      }
    }
  }
}

Migração do ESLint/Prettier

Checklist de Migração

# 1. Instalar o Biome
npm install --save-dev @biomejs/biome

# 2. Inicializar arquivo de configuração
npx @biomejs/biome init

# 3. Migrar configuração do ESLint (automático)
npx @biomejs/biome migrate eslint --write

# 4. Migrar configuração do Prettier (automático)
npx @biomejs/biome migrate prettier --write

Tabela de Correspondência de Regras ESLint

ESLintBiomeCategoria
no-unused-varsnoUnusedVariablescorrectness
no-consolenoConsoleLogsuspicious
eqeqeqnoDoubleEqualssuspicious
prefer-constuseConststyle
no-varnoVarstyle
@typescript-eslint/no-explicit-anynoExplicitAnysuspicious
react-hooks/exhaustive-depsuseExhaustiveDependenciescorrectness
jsx-a11y/alt-textuseAltTexta11y

Estratégia de Migração Gradual

// biome.json - Configuração para migração gradual
{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      // Inicialmente apenas avisos
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "off"  // Desabilitado inicialmente
      }
    }
  }
}
# Remover ESLint/Prettier após migração
npm uninstall eslint prettier eslint-config-prettier eslint-plugin-*

# Remover arquivos de configuração
rm .eslintrc* .prettierrc* .eslintignore .prettierignore

Integração com Editor

VS Code

// .vscode/extensions.json
{
  "recommendations": ["biomejs.biome"]
}
// .vscode/settings.json
{
  // Biome como formatador padrão
  "editor.defaultFormatter": "biomejs.biome",
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

  // Formatar automaticamente ao salvar
  "editor.formatOnSave": true,

  // Executar code actions ao salvar
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },

  // Desabilitar ESLint/Prettier
  "eslint.enable": false,
  "prettier.enable": false
}

Neovim (nvim-lspconfig)

-- init.lua
require('lspconfig').biome.setup({
  cmd = { 'npx', 'biome', 'lsp-proxy' },
  root_dir = require('lspconfig.util').root_pattern('biome.json', 'biome.jsonc'),
  single_file_support = false,
})

-- Integração com null-ls.nvim
local null_ls = require('null-ls')
null_ls.setup({
  sources = {
    null_ls.builtins.formatting.biome,
    null_ls.builtins.diagnostics.biome,
  },
})

JetBrains IDE (WebStorm, etc.)

Passos de configuração:
1. Settings → Languages & Frameworks → JavaScript → Code Quality Tools → Biome
2. Marcar "Enable"
3. Biome package: node_modules/@biomejs/biome
4. Configuration file: biome.json

Configuração de formatação:
1. Settings → Editor → Code Style
2. Desmarcar "Enable EditorConfig support"
3. Settings → Tools → Actions on Save
4. Marcar "Reformat code" e "Run Biome"

Integração com CI/CD

GitHub Actions

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run Biome CI
        run: npx @biomejs/biome ci .

  # Adicionar anotações inline no PR
  lint-review:
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v4

      - name: Setup Biome
        uses: biomejs/setup-biome@v2
        with:
          version: latest

      - name: Run Biome with reviewdog
        uses: reviewdog/action-biome@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          reporter: github-pr-review

GitLab CI

# .gitlab-ci.yml
stages:
  - lint

biome:
  stage: lint
  image: node:20-alpine
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/
  script:
    - npm ci
    - npx @biomejs/biome ci .
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

Hook pre-commit (Husky + lint-staged)

# Instalação do Husky
npm install --save-dev husky lint-staged
npx husky init
// package.json
{
  "lint-staged": {
    "*.{js,jsx,ts,tsx,json,css}": [
      "biome check --write --no-errors-on-unmatched"
    ]
  }
}
# .husky/pre-commit
npx lint-staged

Uso Avançado

API de Plugins (Recurso Experimental)

// biome-plugin.js - Exemplo de regra personalizada
export default {
  name: 'my-custom-rules',
  rules: {
    noTodoComments: {
      meta: {
        docs: {
          description: 'Proíbe comentários TODO em código de produção',
        },
      },
      create(context) {
        return {
          Comment(node) {
            if (node.value.includes('TODO')) {
              context.report({
                node,
                message: 'Comentários TODO devem ser resolvidos antes do merge',
              });
            }
          },
        };
      },
    },
  },
};

Configuração para Monorepo

// biome.json na raiz
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": [],
  "files": {
    "ignore": ["packages/*/dist", "packages/*/node_modules"]
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  },
  "formatter": {
    "enabled": true
  }
}
// packages/web/biome.json - Configuração específica do pacote
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": ["../../biome.json"],
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": "warn"
      }
    }
  }
}

Ordenação Personalizada de Imports

{
  "javascript": {
    "organizeImports": {
      "groups": [
        ["react", "react-dom"],
        ["^@?\\w"],
        ["^@/"],
        ["^\\.\\."],
        ["^\\."]
      ]
    }
  }
}

Solução de Problemas

Problemas Comuns e Soluções

# Limpar cache
rm -rf node_modules/.cache/biome

# Saída detalhada de erros
npx @biomejs/biome check --verbose .

# Debug de arquivo específico
npx @biomejs/biome lint --verbose src/problematic-file.ts

# Validar configuração
npx @biomejs/biome check --config-path biome.json --verbose

Comentários para Suprimir Erros

// Desabilitar regra específica para o arquivo inteiro
// biome-ignore-all lint/suspicious/noExplicitAny: Legacy code

// Desabilitar apenas a próxima linha
// biome-ignore lint/suspicious/noExplicitAny: Necessário para esta API
const data: any = response.data;

// Desabilitar múltiplas regras
// biome-ignore lint/style/useConst lint/correctness/noUnusedVariables: Intencional
let unusedVar = 'test';

// Desabilitar formatação
// biome-ignore format: Manter esta formatação
const matrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

Benchmark de Desempenho

Comparação em projeto de grande escala (10.000 arquivos):

FerramentaTempo de lintTempo de formatUso de Memória
ESLint120s-1,2GB
Prettier-45s800MB
ESLint+Prettier165s(total)2,0GB
Biome2s1,5s150MB
Taxa de Melhoria60x mais rápido30x mais rápido13x de redução

Resumo

O Biome melhora significativamente o toolchain de desenvolvimento frontend.

Benefícios de Adotar o Biome

ItemESLint+PrettierBiome
VelocidadeLentoUltra-rápido (60x+)
Arquivos de configuraçãoMúltiplos1 arquivo
DependênciasMuitas1
Uso de memóriaAltoBaixo
Consistência de configuraçãoPossíveis conflitosIntegrado

Casos Recomendados para Adoção

  • Novos projetos
  • Projetos que precisam acelerar o CI
  • Equipes que buscam simplificar configurações
  • Ambientes Monorepo

O Biome está se tornando o novo padrão no ecossistema JavaScript.

← Voltar para a lista