Linting & Formatting are Non-Negotiable: Biome over ESLint

FeaturedJavaScriptTypeScript
Angus Bosmans
Angus BosmansSoftware Engineer

12 January, 2025

Linting & Formatting are Non-Negotiable: Biome over ESLint

When it comes to Javascript, especially when working in teams, linting and consistent code formatting are non-negotiable. For years, ESLint was the solution to this problem, providing a highly configurable way to format and lint JavaScript code and its various flavours (such as Typescript & JSX). Given the hundreds if not thousands of settings available, many turn to established configs like eslint-config-airbnb-typescript as a base to build their own configs on top of. From here, you can also publish your configuration as a package on NPM with the format eslint-config-<name> to easily re-use it and update it across projects.

The Issue(s) with ESLint

JavaScript on both the web and the server is a constantly evolving language; with new APIs, language features, frameworks and runtimes being dropped seemingly every day. However, what this means for linting is that new rules and parsers are constantly being added and updated to support all the new additions. When you maintain your own config, keeping up with this barrage gets tricky.

I primarily work in Typescript, for the kind of self-documenting code that the type system offers, meaning that my ESLint config needs to support Typescript too. Thus, any base config I choose to extend must support Typescript rules and include a Typescript parser to understand the language features not included in base JavaScript. Furthermore, a config or parser you extend, not to mention ESLint itself will also have its own dependencies, creating a rapidly growing dependency tree for what should be a small part of your application development tooling. In my case, my config @angablue/eslint-config would pull down around 300 packages alone. Yes, I also think that's pretty ridiculous. It's moments like these that make me consider dropping JavaScript for good, until I realise its still the only way to develop a web app.

After hours of wrangling dependencies and config to update my shareable ESLint config, I finally gave up. The straw that broke the camel's back was the aforementioned eslint-config-airbnb-typescript that was recently deprecated as the original author found maintaining the repository to be too time consuming and relentless. Now I'm not blaming the author or maintainers of eslint-config-airbnb-typescript, as without their work, other config authors would have a lot more work ahead of them to get up and running. ESLint was updated to version 9, with the major version bump signalling a lot of breaking changes to existing plugins and configs. While breaking changes is nothing unsurmountable, what is is updating the roughly 300 package that my config directly or indirectly depends upon. Initially I waited until slowly one-by-one, packages updated to support eslint@9, with each day bringing the ecosystem closer to the point when I could finally update my own config. However, after days, weeks, months and now what is nearly a year, we still weren't ready. That's when I got this message from a long-time colleague:

Discord messages of my colleague introducing me to Biome.js
The spark to transition to Biome.

Bye-bye ESLint! Hello Biome!

Written in Rust, the JavaScript tooling world's favourite child, Biome aims to replace ESLint and Prettier with a solution that learns from the mistakes of its predecessors. Its main claim to fame ~35 times faster formatting and linting (which I can attest to, does hold up in real, large projects), but it also includes first-class support for Typescript and JSX - a must have for my use cases. This is huge. No longer do we need to import new parsers and configs to create a linting system that works for what are now ubiquitous technologies.

After thoroughly reading through the docs, I decided to start putting together my own config, migrating my settings from my old ESLint config. While Biome does have a tool for this exact scenario, I found it didn't fare so well porting over various rules from obscure plugins, so I did what any sane person would and went through every default-disabled rule on Biome and flipped certain rules on one at a time. This endeavour took the better part of an afternoon, but in the end I had my very own config, @angablue/biome-config. Sitting pretty at just under 100 lines of JSON, this config defined exactly how I wanted my code to look and behave. That's it. No plugins, no base configs, no dependencies.

My Biome config on NPM.
0 dependencies. 4 files.

The config has exactly one peer dependency, @biomejs/biome aka, Biome itself. As JavaScript develops and so does Biome, this means I will only have to follow one project; Biome.

Since creating this config, I've switched all my active projects both work and personal to Biome and have had no qualms. The toolchain includes popular editor integrations, enabling red squigglies with accompanying and helpful warnings and automatic refactoring suggestions. Furthermore, I mentioned earlier that Biome is fast. At BloxBoom, we used to lint and format our ~30,000 line codebase with ESLint which would entail waiting around for 30 seconds while the JavaScript based linter slowly worked its way through the repo. With Biome, the story is completely different, the entire project is linted and formatted in under 1 second.

Biome Forever (or at least for the foreseeable future...)

In conclusion, Biome emerges as a compelling alternative to ESLint and Prettier, offering a one-stop-shop for linting and formatting in JavaScript projects. Biome really excels in these areas:

  • Performance: Biome is built with Rust, providing significant speed improvements over JavaScript-based tools. This results in faster linting and formatting processes, enhancing developer productivity.
  • First-Class TypeScript and JSX Support: Biome offers out-of-the-box support for TypeScript and JSX, eliminating the need for additional parsers or configurations.
  • Minimal Configuration: Biome operates with zero configuration with sensible defaults, by the customisation is there if you want it.
  • Reduced Dependency Overhead: With Biome, the dependency tree is entirely eliminated, removing the bloated node_modules folder that comes with ESLint.

With all that said, this might read like an ad, but it truly isn't, I just enjoy the tech, and for my part, I'm happy to escape dependency hell.