I migrate from ESLint, Prettier to Biome

Published:

4 min read


History

A couple days ago, I saw Biome from forum, I looked through the website and looks promising. This might become Es-Lint replacement I guess. The history was when I running ESLint on my project but still got a warning message, my package was deprecated & need to update soon. Seem this happened too often, and sometimes I got confused between ESLint & Prettier configurations, sometimes not compatible or conflict with each other. So I think it’s time to look for an alternative.

After deep read Biome website documentation, history & their story. I decided to migrate my small project to Biome. But after all I need some test how fast & how simple their process to migrate my current project using (EsLint & Prettier) into a single Biome configuration.


Migrate process

The migrating process is very quite simple actually, all you need to do is install Biome & run their command. Biome also provides how to migrate from ESLint and Prettier with your current configuration of ESLint & Prettier with ease process migration.

Setup:

Here is steps to migrate my current ESLint & Prettier:

  1. Install Biome npm install --save-dev --save-exact @biomejs/biome
  2. Run their migrate command npx @biomejs/biome migrate eslint --write
  3. Biome will generate new file with our current ESLint & Prettier settings. biome.json
My generated biome.json file
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "vcs": {
    "enabled": false,
    "clientKind": "git",
    "useIgnoreFile": false
  },
  "files": {
    "ignoreUnknown": false,
    "ignore": ["./dist"]
  },
  "formatter": {
    "enabled": true,
    "useEditorconfig": true,
    "formatWithErrors": false,
    "indentStyle": "tab",
    "indentWidth": 4,
    "lineEnding": "lf",
    "lineWidth": 100,
    "attributePosition": "auto",
    "bracketSpacing": true,
    "ignore": [
      "**/node_modules",
      "**/dist",
      "**/.env",
      "**/.gitignore",
      "**/.prettierignore",
      "**/.browserslistrc",
      "public/css",
      "public/font",
      "public/fonts",
      "public/js",
      "**/*.snap",
      "**/*.gif",
      "**/*.jpeg",
      "**/*.jpg",
      "**/*.png",
      "**/*.svg",
      "**/*.ico"
    ]
  },
  "organizeImports": {
    "enabled": true
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": false,
      "complexity": {
        "noExtraBooleanCast": "error",
        "noMultipleSpacesInRegularExpressionLiterals": "error",
        "noUselessCatch": "error",
        "noWith": "error"
      },
      "correctness": {
        "noConstAssign": "error",
        "noConstantCondition": "error",
        "noEmptyCharacterClassInRegex": "error",
        "noEmptyPattern": "error",
        "noGlobalObjectCalls": "error",
        "noInnerDeclarations": "error",
        "noInvalidConstructorSuper": "error",
        "noNewSymbol": "error",
        "noNonoctalDecimalEscape": "error",
        "noPrecisionLoss": "error",
        "noSelfAssign": "error",
        "noSetterReturn": "error",
        "noSwitchDeclarations": "error",
        "noUndeclaredVariables": "error",
        "noUnreachable": "error",
        "noUnreachableSuper": "error",
        "noUnsafeFinally": "error",
        "noUnsafeOptionalChaining": "error",
        "noUnusedLabels": "error",
        "noUnusedVariables": "error",
        "useIsNan": "error",
        "useValidForDirection": "error",
        "useYield": "error"
      },
      "style": {
        "useBlockStatements": "off"
      },
      "suspicious": {
        "noAsyncPromiseExecutor": "warn",
        "noCatchAssign": "error",
        "noClassAssign": "error",
        "noCompareNegZero": "error",
        "noControlCharactersInRegex": "error",
        "noDebugger": "error",
        "noDuplicateCase": "error",
        "noDuplicateClassMembers": "error",
        "noDuplicateObjectKeys": "error",
        "noDuplicateParameters": "error",
        "noEmptyBlockStatements": "error",
        "noFallthroughSwitchClause": "error",
        "noFunctionAssign": "error",
        "noGlobalAssign": "error",
        "noImportAssign": "error",
        "noMisleadingCharacterClass": "error",
        "noPrototypeBuiltins": "warn",
        "noRedeclare": "error",
        "noShadowRestrictedNames": "error",
        "noSparseArray": "error",
        "noUnsafeNegation": "error",
        "useGetterReturn": "error",
        "useValidTypeof": "error"
      }
    }
  },
  "javascript": {
    "formatter": {
      "jsxQuoteStyle": "double",
      "quoteProperties": "asNeeded",
      "trailingCommas": "all",
      "semicolons": "always",
      "arrowParentheses": "always",
      "bracketSameLine": false,
      "quoteStyle": "double",
      "attributePosition": "auto",
      "bracketSpacing": true
    }
  }
}
  1. Add new script Biome lint/formatter to integrate with npm script, this script below will automatically fix & format code.
"scripts": {
	"format": "npx biome check --fix --unsafe"
},
  1. Optional: you can remove all related ESLint & Prettier configuration to maintain your project keep clean.

Result:

After migration step completed, I tried run formatter the result very extremely fast as they promised. formatter result


Drawback

“There is no ivory that is not cracked” is a proverb that describes perfection. The project is young and can’t compete against giants such as Prettier, ESLint, Webpack, Vite, ESBuild, etc.. I still encounter problems such as:

language support

Wrapping up

Honestly I really like this tool, it’s so lightweight, fast and simple. I will consider to use this tool in the future.

But Biome still young tool to compete 1:1 with big projects such as ESLint, Vite, etc.. But when I read their commitment, roadmap, download trend, and Biome can beat challenge from prettier. Seems We can give a chance for this project to beat the competition & blossom. Keep stay tune.

For more detail information you can read completely at Biome documentation.