Biome 15 🧹 Migrating from ESLint — biome migrate eslint
The biome migrate eslint command is the automated bridge between an ESLint configuration and a Biome configuration. It reads the .eslintrc or the eslint.config.js file, follows the extends chains, loads the shared and the plugin configurations, and writes the equivalent rules and settings into the biome.json . The command is the first step of the migration, and the manual review is the second. The output is not a perfect reproduction of the ESLint behavior, because Biome does not implement every rule option and deliberately diverges in some cases . The review is the mechanism that catches the differences.
The command’s most important behavior is the rule-preset replacement. It does not append the migrated rules to the existing configuration. It sets the recommended preset to false and enables only the rules that it successfully migrated . The replacement is the mechanism that keeps the configuration honest: the rules that Biome could not migrate are not silently enabled by the recommended preset, and the developer sees exactly which rules are active. The migrated rules are the explicit set, and the set is the result of the translation.
Key point: biome migrate eslint --write reads the ESLint configuration, follows the extends chains, loads the plugins, and writes the equivalent rules into the biome.json. It sets the recommended preset to false and enables only the migrated rules. By default, it migrates only the identical rules; the --include-inspired flag adds the inspired rules. The .eslintignore patterns become the files.includes exceptions, and the VCS integration must be enabled to keep the .gitignore behavior.
Why the migration is not a one-to-one translation
The identical-versus-inspired problem. Biome’s rules are either identical to their ESLint sources or only inspired by them . An identical rule produces the same diagnostics and the same fixes as the ESLint rule. An inspired rule produces the similar diagnostics but may differ in the options, the edge cases, or the fix behavior. The command migrates only the identical rules by default, because the inspired rules are the ones that can change the behavior unexpectedly . The --include-inspired flag is the mechanism that opts into the broader set, and the broader set is the trade-off against the precision.
The naming-convention problem. Biome uses the camelCaseRuleName while ESLint uses the kebab-case-rule-name . The no-double-equals becomes the noDoubleEquals, and the no-unused-vars becomes the noUnusedVariables. The command handles the naming translation, and the translation is the mechanism that maps the ESLint rule to the Biome rule. The rule-source page is the reference for the mapping, and the page is the mechanism that documents the origin.
The option problem. Some Biome rules do not implement every ESLint option. The command migrates the rule with the options it supports, and the options that it does not support are dropped . The dropped options are the silent difference, and the difference is the reason the migration guide recommends the review. The review is the mechanism that catches the behavior change that the option dropping causes.
The plugin problem. The command loads the shared and the plugin configurations, and it supports the TypeScript ESLint, the ESLint JSX A11y, the ESLint React, and the ESLint Unicorn . The plugins that Biome does not support are the ones that the command cannot migrate, and the rules from those plugins must be configured by hand . The manual configuration is the mechanism that covers the gap, and the gap is the reason the migration is not the complete for the projects with the niche plugins.
The cyclic-reference problem. Some plugins and shared configurations export objects with the cyclic references, and Biome cannot load them . The migration fails with the error, and the workaround is to comment out the plugins and the shared configurations, run the migration, and then restore them one at a time to find the responsible one . The one-at-a-time restoration is the mechanism that isolates the problem, and the isolation is the reason the migration can proceed for the rest of the configuration.
a. The command and the configuration output
The command is the three-word invocation with the --write flag. The flag is the mechanism that writes the output to the biome.json instead of printing it.
# The ESLint migration
biome migrate eslint --write
The command reads the legacy .eslintrc or the flat eslint.config.js. It follows the extends field, loads the shared and the plugin configurations, and migrates the .eslintignore . The --write flag is the mechanism that applies the output, and the command without the flag is the preview.
// The ESLint configuration
{
"extends": ["plugin:unicorn/recommended"],
"plugins": ["unicorn"],
"ignore_patterns": ["dist/**"],
"globals": {
"Global1": "readonly"
},
"rules": {
"eqeqeq": "error"
}
}
// The migrated biome.json (simplified)
{
"linter": {
"rules": {
"recommended": false,
"suspicious": {
"noDoubleEquals": "error"
}
}
},
"javascript": {
"globals": ["Global1"]
},
"files": {
"includes": ["!dist/**"]
}
}
The recommended: false is the replacement mechanism, and the noDoubleEquals: "error" is the migrated rule . The ignore_patterns becomes the files.includes exception, and the globals becomes the javascript.globals array. The output is the explicit set, and the set is the translation.
The --include-inspired flag is the second option. The flag migrates the inspired rules as well as the identical ones.
# The migration with the inspired rules
biome migrate eslint --include-inspired --write
The flag is the mechanism that adds the inspired rules to the output, and the addition is the trade-off against the precision. The inspired rules may behave differently from the ESLint sources, and the difference is the reason the flag is opt-in .
b. The VCS integration and the post-migration review
The VCS integration is the separate step that the migration does not do automatically. The vcs.useIgnoreFile: true is the flag that makes Biome read the .gitignore, and the flag is the mechanism that keeps the ignore behavior consistent with ESLint .
// biome.json — the VCS integration
{
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
}
}
The enabled and the clientKind are the required fields, and the useIgnoreFile is the flag that enables the .gitignore reading. The migration guide states the requirement explicitly: “ESLint, Prettier, and Stylelint skip the files in your .gitignore by default. Biome does so only when its VCS integration is enabled, so enable it to keep the same set of files ignored” . The enablement is the mechanism that keeps the ignored files ignored, and the explicit step is the reason the migration is not the complete.
The post-migration review is the manual step. The command writes the rules, and the developer checks the output against the expected behavior. The review is the mechanism that catches the known differences: the identical-versus-inspired gap, the dropped options, and the plugin rules that the command could not migrate . The review is the reason the migration is not the one-command-and-done, and the review is the step that the documentation recommends.
The removal of the ESLint dependencies is the final step. The migration guide states: “Once you are satisfied with the result, remove ESLint, Prettier, Stylelint, and their plugins from your dependencies, and replace their editor extensions with Biome’s” . The removal is the mechanism that completes the migration, and the editor extension replacement is the mechanism that keeps the format-on-save and the diagnostics working.
The editor integration is the separate concern. The VS Code settings need the editor.defaultFormatter: "biomejs.biome" and the editor.codeActionsOnSave with the source.fixAll.biome to replace the ESLint extension. The removal of the ESLint plugins is the mechanism that removes the redundant dependencies, and the eslint-config-prettier is not needed because Biome has no formatter-linter conflict .
Complete Example Session
// ============================================
// PART 1: THE ESLINT CONFIGURATION
// ============================================
// .eslintrc.json
{
"extends": ["eslint:recommended", "plugin:react/recommended"],
"plugins": ["react"],
"ignorePatterns": ["dist/**", "coverage/**"],
"globals": {
"process": "readonly"
},
"rules": {
"eqeqeq": "error",
"no-var": "error",
"no-console": "warn"
}
}
// ============================================
// PART 2: THE MIGRATION COMMAND
// ============================================
// biome migrate eslint --write
// The command reads the .eslintrc.json.
// It follows the extends and loads the plugins.
// The output is the biome.json with the migrated rules.
// ============================================
// PART 3: THE MIGRATED CONFIGURATION
// ============================================
// biome.json (simplified)
{
"linter": {
"rules": {
"recommended": false,
"suspicious": {
"noDoubleEquals": "error"
},
"style": {
"noVar": "error"
}
}
},
"javascript": {
"globals": ["process"]
},
"files": {
"includes": ["!dist/**", "!coverage/**"]
}
}
// The recommended preset is disabled.
// Only the migrated rules are enabled.
// ============================================
// PART 4: THE INCLUDED-INSPIRED FLAG
// ============================================
// biome migrate eslint --include-inspired --write
// The inspired rules are also migrated.
// The output has more rules, and the review is more important.
// ============================================
// PART 5: THE VCS INTEGRATION
// ============================================
// biome.json — the added VCS configuration
{
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
}
}
// The .gitignore is respected.
// ============================================
// PART 6: THE CYCLIC REFERENCE WORKAROUND
// ============================================
// The migration fails with the cyclic reference error.
// The plugin is commented out, and the migration is rerun.
// The plugin is restored after the migration.
// ============================================
// PART 7: THE MANUAL RULE CONFIGURATION
// ============================================
// The plugin that Biome does not support is configured by hand.
// The rules are added to the biome.json manually.
// ============================================
// PART 8: THE DEPENDENCY REMOVAL
// ============================================
// npm uninstall eslint eslint-plugin-react
// The ESLint dependencies are removed after the review.
// ============================================
// PART 9: THE EDITOR REPLACEMENT
// ============================================
// The ESLint extension is disabled.
// The Biome extension is enabled.
// The editor.defaultFormatter is "biomejs.biome".
// ============================================
// PART 10: THE CHECKLIST
// ============================================
// [ ] The migration command is run with --write.
// [ ] The recommended preset is false.
// [ ] The migrated rules are reviewed.
// [ ] The --include-inspired flag is used if the broader set is wanted.
// [ ] The VCS integration is enabled for the .gitignore.
// [ ] The cyclic reference is handled.
// [ ] The unsupported plugin rules are configured by hand.
// [ ] The ESLint dependencies are removed.
// [ ] The editor extension is replaced.
The ten parts covered the ESLint configuration, the migration command, the migrated configuration, the --include-inspired flag, the VCS integration, the cyclic reference workaround, the manual rule configuration, the dependency removal, the editor replacement, and the checklist. The through-line is that the command ports the rules, and the review catches the differences.
Quick Reference
The migration command
| Command | Purpose |
|---|---|
biome migrate eslint | The preview |
biome migrate eslint --write | The write |
biome migrate eslint --include-inspired --write | The write with the inspired rules |
The supported inputs
| Input | Support |
|---|---|
The legacy .eslintrc | Yes |
The flat eslint.config.js | Yes |
The .eslintignore | Yes |
| The YAML configuration | No |
The supported plugins
| Plugin | Support |
|---|---|
| The TypeScript ESLint | Yes |
| The ESLint JSX A11y | Yes |
| The ESLint React | Yes |
| The ESLint Unicorn | Yes |
The post-migration steps
| Step | Purpose |
|---|---|
| Enable the VCS | Keep the .gitignore behavior |
| Review the output | Catch the known differences |
| Configure the unsupported plugins by hand | Cover the gap |
| Remove the dependencies | Complete the migration |
| Replace the editor extension | Keep the diagnostics and the format on save |
Best Practices
✅ Do This:
# Use the --write flag to apply the migration
biome migrate eslint --write // ✅
// Enable the VCS integration for the .gitignore
{ "vcs": { "enabled": true, "clientKind": "git", "useIgnoreFile": true } } // ✅
❌ Don’t Do This:
# Assume the migration is a drop-in replacement
biome migrate eslint // the known differences remain // ❌
# Skip the VCS integration
// The .gitignore files are processed // ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| The rule is missing | The command migrates only the identical rules | Use the --include-inspired flag |
| The behavior differs | The rule is inspired, not identical | Review the rule source page |
| The migration fails | The plugin has the cyclic reference | Comment out the plugin and rerun |
The .gitignore is not respected | The VCS integration is disabled | Enable the vcs.useIgnoreFile |
| The rule option is ignored | The option is not implemented in Biome | Configure the rule by hand |
Real-World Examples
1. The migration command
biome migrate eslint --write
2. The inspired rules
biome migrate eslint --include-inspired --write
3. The recommended preset
{ "linter": { "rules": { "recommended": false } } }
4. The migrated rule
{ "linter": { "rules": { "suspicious": { "noDoubleEquals": "error" } } } }
5. The globals
{ "javascript": { "globals": ["process"] } }
6. The ignore patterns
{ "files": { "includes": ["!dist/**"] } }
7. The VCS integration
{ "vcs": { "useIgnoreFile": true } }
8. The cyclic reference
The plugin is commented out and the migration is rerun.
9. The dependency removal
npm uninstall eslint eslint-plugin-react
10. The editor replacement
{ "editor.defaultFormatter": "biomejs.biome" }
Visual
The Migration Flow
┌──────────────────────────────────────────────────────────────┐
│ THE MIGRATION FLOW │
│ │
│ The .eslintrc or the eslint.config.js │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ biome migrate │ The command reads the config │
│ │ eslint --write │ and writes the biome.json │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ The biome.json with │ The recommended: false │
│ │ the migrated rules │ The explicit rules │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ The manual review │ The known differences │
│ │ The VCS integration │ The plugin gap │
│ └─────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
The Identical vs Inspired Rules
┌──────────────────────────────────────────────────────────────┐
│ THE IDENTICAL VS INSPIRED │
│ │
│ The identical rule: │
│ ┌─────────────────────┐ │
│ │ The same behavior │ The migrated by default │
│ │ The same fixes │ │
│ └─────────────────────┘ │
│ │
│ The inspired rule: │
│ ┌─────────────────────┐ │
│ │ The similar │ The migrated only with the │
│ │ behavior │ --include-inspired flag │
│ │ The different edge │ │
│ └─────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
The Recommended Preset
┌──────────────────────────────────────────────────────────────┐
│ THE RECOMMENDED PRESET │
│ │
│ Before the migration: │
│ ┌─────────────────────┐ │
│ │ recommended: true │ The Biome default │
│ └─────────────────────┘ │
│ │
│ After the migration: │
│ ┌─────────────────────┐ │
│ │ recommended: false │ The migrated rules only │
│ └─────────────────────┘ │
│ │
│ The replacement keeps the configuration honest. │
└──────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| The command | biome migrate eslint --write |
| The input | The .eslintrc, the eslint.config.js, the .eslintignore |
| The output | The biome.json with the migrated rules |
| The preset | The recommended: false with the explicit rules |
| The identical rules | The migrated by default |
| The inspired rules | The migrated only with the --include-inspired flag |
| The supported plugins | The TypeScript ESLint, the JSX A11y, the React, the Unicorn |
| The post-migration | The VCS integration, the review, the dependency removal |
Key takeaways:
- The command ports the rules, the globals, the overrides, and the ignore patterns. The
biome migrate eslint --writereads the ESLint configuration, follows theextendschains, loads the plugins, and writes the equivalent rules into thebiome.json. The.eslintignorepatterns become thefiles.includesexceptions. - The command replaces the linter settings and disables the recommended preset. It sets the
recommendedtofalseand enables only the migrated rules. The replacement is the mechanism that keeps the configuration honest, and the explicit set is the result of the translation . - The identical rules are migrated by default, the inspired rules only with the flag. The inspired rules may behave differently, and the
--include-inspiredflag is the mechanism that opts into the broader set. The review is the mechanism that catches the differences . - The VCS integration is the separate step. ESLint skips the
.gitignorefiles by default, and Biome does so only when thevcs.useIgnoreFileis enabled. The enablement is the mechanism that keeps the ignored files ignored . - The unsupported plugins must be configured by hand. The command supports the TypeScript ESLint, the JSX A11y, the React, and the Unicorn, and the other plugins are the manual configuration. The cyclic reference is the workaround, and the one-at-a-time restoration is the isolation mechanism .
Remember: The Biome ESLint migration is the command that ports the configuration, and the review that catches the differences. The biome migrate eslint --write reads the ESLint files and writes the Biome configuration with the explicit rules. The VCS integration keeps the ignore behavior, the review catches the known differences, and the dependency removal completes the switch. The migration is the sequence, and the sequence is the complete.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!