Llega Biome 2.0 - Cadena de herramientas ultra rápida que reemplaza ESLint/Prettier

2025.12.02

Biome es una cadena de herramientas ultra rápida para JavaScript/TypeScript escrita en Rust. Integra las funciones de ESLint y Prettier en una sola herramienta, mejorando la experiencia de desarrollo con una velocidad abrumadora. En 2025, con el lanzamiento de Biome 2.0, su adopción está avanzando en más proyectos.

¿Qué es Biome?

Comparación de cadenas de herramientas

flowchart TB
    subgraph Traditional["Configuración tradicional"]
        Workflow1["Flujo de desarrollo"]
        ESLint["ESLint<br/>(JavaScript)"]
        Prettier["Prettier<br/>(JavaScript)"]
        TSC["TypeScript<br/>tsc"]
        Config1["Se necesitan múltiples archivos de configuración<br/>(.eslintrc, .prettierrc, tsconfig.json)"]

        Workflow1 --> ESLint
        Workflow1 --> Prettier
        Workflow1 --> TSC
        ESLint --> Config1
        Prettier --> Config1
        TSC --> Config1
    end
flowchart TB
    subgraph BiomeArch["Configuración de Biome"]
        Workflow2["Flujo de desarrollo"]
        Biome["Biome (Rust)<br/>✓ Linter<br/>✓ Formatter<br/>✓ Import Sort"]
        Config2["Gestión con 1 archivo biome.json"]

        Workflow2 --> Biome --> Config2
    end

Comparación de rendimiento

HerramientaProcesamiento de 1000 archivosUso de memoria
ESLint + PrettierAprox. 30s~500MB
BiomeAprox. 0.5s~50MB

Aproximadamente 60 veces más rápido, 1/10 de memoria

Instalación y configuración

Instalación 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

# Inicialización del archivo de configuración
npx @biomejs/biome init

Archivo de configuración 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"
    }
  }
}

Configuración de scripts en 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 ."
  }
}

Configuración detallada

Ejemplo de configuración 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"
          }
        }
      }
    }
  ]
}

Categorías de reglas del Linter

Lista de categorías de reglas

CategoríaEjemplo de reglaDescripción
a11y (Accesibilidad)useAltTextRequiere atributo alt en imágenes
useKeyWithClickEventsOperación de teclado para eventos de clic
complexity (Complejidad)noBannedTypesDetecta uso de tipos prohibidos
noForEachRecomienda forEach → for…of
noExcessiveCognitiveComplexityLímite de complejidad cognitiva
correctness (Corrección)noUnusedVariablesDetección de variables no usadas
noUnusedImportsDetección de imports no usados
useExhaustiveDependenciesArray de dependencias de useEffect
performance (Rendimiento)noAccumulatingSpreadProhibir acumulación de spread
noDeleteAdvertir uso de operador delete
security (Seguridad)noDangerouslySetInnerHtmlDetección de vulnerabilidades XSS
noGlobalEvalProhibir uso de eval()
style (Estilo)useConstUsar const para variables sin reasignación
useTemplateTemplate literal sobre concatenación de strings
noParameterAssignProhibir reasignación a parámetros
suspicious (Código sospechoso)noExplicitAnyAdvertir uso de tipo any
noConsoleLogAdvertir uso de console.log
noDebuggerProhibir sentencias debugger

Ejemplo de configuración detallada de reglas

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

Migración desde ESLint/Prettier

Lista de verificación de migración

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

# 2. Inicializar archivo de configuración
npx @biomejs/biome init

# 3. Migración desde configuración ESLint (automática)
npx @biomejs/biome migrate eslint --write

# 4. Migración desde configuración Prettier (automática)
npx @biomejs/biome migrate prettier --write

Tabla de correspondencia de reglas ESLint

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

Estrategia de migración gradual

// biome.json - Configuración para migración gradual
{
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      // Inicialmente solo advertencias
      "correctness": {
        "noUnusedVariables": "warn",
        "noUnusedImports": "warn"
      },
      "suspicious": {
        "noExplicitAny": "warn",
        "noConsoleLog": "off"  // Deshabilitado inicialmente
      }
    }
  }
}
# Eliminar ESLint/Prettier después de la migración
npm uninstall eslint prettier eslint-config-prettier eslint-plugin-*

# Eliminar archivos de configuración
rm .eslintrc* .prettierrc* .eslintignore .prettierignore

Integración con editores

VS Code

// .vscode/extensions.json
{
  "recommendations": ["biomejs.biome"]
}
// .vscode/settings.json
{
  // Biome como formateador predeterminado
  "editor.defaultFormatter": "biomejs.biome",
  "[javascript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },

  // Auto-formatear al guardar
  "editor.formatOnSave": true,

  // Ejecutar acciones de código al guardar
  "editor.codeActionsOnSave": {
    "quickfix.biome": "explicit",
    "source.organizeImports.biome": "explicit"
  },

  // Deshabilitar 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,
})

-- Integración con 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.)

Pasos de configuración:
1. Settings → Languages & Frameworks → JavaScript → Code Quality Tools → Biome
2. Marcar "Enable"
3. Biome package: node_modules/@biomejs/biome
4. Configuration file: biome.json

Configuración de formato:
1. Settings → Editor → Code Style
2. Desactivar "Enable EditorConfig support"
3. Settings → Tools → Actions on Save
4. Marcar "Reformat code" y "Run Biome"

Integración 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 .

  # Agregar anotaciones inline al 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)

# Instalar 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 avanzado

API de plugins (función experimental)

// biome-plugin.js - Ejemplo de regla personalizada
export default {
  name: 'my-custom-rules',
  rules: {
    noTodoComments: {
      meta: {
        docs: {
          description: 'Disallow TODO comments in production code',
        },
      },
      create(context) {
        return {
          Comment(node) {
            if (node.value.includes('TODO')) {
              context.report({
                node,
                message: 'TODO comments should be resolved before merge',
              });
            }
          },
        };
      },
    },
  },
};

Configuración de Monorepo

// biome.json en la raíz
{
  "$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 - Configuración específica del paquete
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "extends": ["../../biome.json"],
  "linter": {
    "rules": {
      "correctness": {
        "useExhaustiveDependencies": "warn"
      }
    }
  }
}

Ordenamiento personalizado de imports

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

Solución de problemas

Problemas comunes y soluciones

# Limpiar caché
rm -rf node_modules/.cache/biome

# Salida de error detallada
npx @biomejs/biome check --verbose .

# Depurar archivo específico
npx @biomejs/biome lint --verbose src/problematic-file.ts

# Validar configuración
npx @biomejs/biome check --config-path biome.json --verbose

Comentarios de supresión de errores

// Deshabilitar regla específica en todo el archivo
// biome-ignore-all lint/suspicious/noExplicitAny: Legacy code

// Deshabilitar solo la siguiente línea
// biome-ignore lint/suspicious/noExplicitAny: Necessary for this API
const data: any = response.data;

// Deshabilitar múltiples reglas
// biome-ignore lint/style/useConst lint/correctness/noUnusedVariables: Intentional
let unusedVar = 'test';

// Deshabilitar formato
// biome-ignore format: Keep this formatting
const matrix = [
  [1, 0, 0],
  [0, 1, 0],
  [0, 0, 1],
];

Benchmark de rendimiento

Comparación en proyecto grande (10,000 archivos):

HerramientaTiempo lintTiempo formatUso memoria
ESLint120s-1.2GB
Prettier-45s800MB
ESLint+Prettier165s(total)2.0GB
Biome2s1.5s150MB
Mejora60x más rápido30x más rápido13x menos

Resumen

Biome mejora significativamente la cadena de herramientas de desarrollo frontend.

Beneficios de adoptar Biome

AspectoESLint+PrettierBiome
VelocidadLentaUltra rápida (60x+)
Archivos de configMúltiples1 archivo
DependenciasMuchas1
Uso de memoriaAltoBajo
Consistencia de configPosible conflictoIntegrada

Casos de uso recomendados

  • Nuevos proyectos
  • Proyectos que necesitan acelerar CI
  • Equipos que buscan simplificar configuración
  • Entornos Monorepo

Biome se está convirtiendo en el nuevo estándar del ecosistema JavaScript.

Enlaces de referencia

← Volver a la lista