Podcast Archives · 2026-06-18 · 1h 3m
Key moments - from our scoring
Substance score
54 / 100
Five dimensions, 20 points each
Emmanuel Stopa, creator of Biome and senior systems engineer at Cloudflare, discusses the evolution of JavaScript tooling and why he built Biome as a unified alternative to Prettier and ESLint. The conversation covers bundlers and formatters, the architecture challenges that led Rome (Biome's predecessor) to migrate from TypeScript to Rust, and the fundamental design tradeoffs in tooling. Stopa explains how plugin systems create maintenance debt - citing ESLint's recent flat config overhaul and webpack's performance struggles - and why Biome takes an opinionated, batteries-included approach instead. For engineering leaders and tool maintainers wrestling with configuration sprawl, JavaScript performance bottlenecks, or decisions between extensibility and developer experience, this episode offers firsthand insights into building native-speed developer tools and the hard lessons from the webpack, Rollup, and ESLint ecosystems.
Rust provides three key advantages: strict type safety reducing dependency breaking changes, native memory management enabling sustained performance (Rome in TypeScript consumed 8GB of memory during bundling), and easy WebAssembly integration via the WASM bindgen crate.
Biome unifies formatting and linting into a single, opinionated tool with sensible defaults and minimal configuration, replacing the overhead of maintaining separate tools like Prettier and ESLint while providing cross-file analysis through a module graph.
A bundler identifies entry points (pages), then traverses a tree of dependencies including CSS files, components, and JavaScript files, managing asset order and script execution to ensure styles and scripts render and execute correctly without conflicts.
ESLint's recursive plugin configuration became difficult to debug and prevented innovation, so the team redesigned it to static, flat configuration for predictability and maintainability, a breaking change Stopa argues was necessary despite user friction.
Plugin systems degrade tool performance, make optimization harder, and lock maintainers into backward compatibility, preventing the innovation and experimentation that developers find rewarding - as shown by webpack's thousand-line configs and ESLint's inability to innovate due to plugin ecosystem constraints.
Our reviewer’s read on each dimension, with quotes from the episode.
There are genuine technical insights buried in the episode - type inference without the TypeScript compiler, the module graph vs semantic model distinction, and the CSS class usage lint rule - but a large portion of the runtime is spent on basic explanations (what is a bundler, origin-story narrative) that offer little to an experienced operator. The insight-to-filler ratio is modest for a 63-minute episode.
Biome is able to scan the whole project, CS files, jarstri files, view files, all the files, it collects all the information and then it does the lint rule that inspects...It reads the classes that you used and it checks if they're actually defined somewhere in your project
the engine relies heavily on the model graph in order to essentially collect and read all the files that the project uses, as well as um, the dependencies
The observation that plugin extensibility creates an innovation trap for maintainers is the freshest take in the episode, and the push for static configurations over dynamic ones is a coherent position. However, the broader narrative - Rust for performance/memory safety, one-tool-to-rule-them-all philosophy, SSR-as-old-PHP - are recurring industry talking points not unique to this episode.
the force of eslint comes from its plugin system, but now they can't innovate, they can't try new things because otherwise all these plugins they could break
configurations should be static, it shouldn't be dynamic
Emma is the actual creator and lead maintainer of Biome, a Cloudflare engineer, and an Astro lead - genuinely relevant practitioner experience who has shipped the tools under discussion. The credibility is real, though the conversation doesn't consistently probe the deepest layers of her technical expertise, leaving some depth on the table.
Eventually the company behind it went under so they couldn't get any more money...we had to do it because the NPM tokens expired so we couldn't actually ship and publish new versions on NPM anymore
I fixed a bug where biome couldn't infer the type of dependency. So there was import function from Lodash for example and he couldn't understand if it was a promise or not
The episode contains a handful of concrete data points - 8GB memory for Rome in TypeScript, 97% Prettier formatting parity, 70+ user GritQL plugins, 100% CommonMark coverage - which are meaningful. However, these specifics are scattered across a transcript that frequently falls back on vague language ('a lot of things,' 'things like that') and lacks named benchmarks, timelines, or adoption metrics.
was consuming a lot of memory, like 8 gigs of memory
we match 97% of pretty s formatting
Josh occasionally leverages his own TypeScript/ESLint background to ask technically grounded follow-ups - the semantic model vs. module graph distinction and the plugin interoperability challenge are good prompts. But many questions are broad setup questions or gentle softballs, and there is virtually no pushback or challenge to any of Emma's claims throughout the interview.
What's the difference between a semantic graph and a module graph?
So it sounds like you could use code fixes from Lint Rules as a sort of code mod tool
Computed from the transcript - who did the talking, and the words that came up most.
Modern web development requires an ever-growing collection of tools including formatters, linters, bundlers, and plugins. Each tool typically has its own configuration, dependencies, and performance cost. As applications grow more complex, the overhead of maintaining this toolchain becomes a real burden. Biome is an open source toolchain for web projects that brings formatting and linting together in a single fast, opinionated tool. It's built in Rust and is designed to be a drop-in replacement for Prettier and ESLint, with sensible defaults, minimal configuration, and consistent behavior across the CLI and editor environments. Biome also introduces a module graph that enables cross-file analysis, and type-aware lint rules that don't require the TypeScript compiler. Emanuele Stoppa , known as Ema, is a Senior Systems Engineer at Cloudflare, a lead at Astro, and the creator and lead maintainer of Biome. In this episode, Ema joins Josh Goldberg to discuss the history of Biome, how linters and formatters work under the hood, what makes Biome's architecture fundamentally different from the tools it replaces, and what's coming next for the project and its community.
Transcribed and scored by The B2B Podcast Index.
Narrator: Modern web development requires an ever growing collection of tools including formatters, linters, bundlers and plugins. Each tool typically has its own configurations, dependencies and performance cost. As applications grow more complex, the overhead of maintaining this tool chain becomes a real burden. Biome is an open source toolchain for web projects that brings formatting and linting together in a single fast, opinionated tool. It's built in Rust and is designed to be a drop in replacement for Prettier and eslint, with sensible defaults, minimal configuration, and consistent behavior across the CLI and editor environments. Biome UM also introduces a module graph that enables cross file analysis and type aware lint rules that don't require the TypeScript compiler. Amanuela Stapa, known as Emma, is a senior systems engineer at Cloudflare, a lead at Astro, and the creator and lead maintain of Biome. In this episode, Emma joins Josh Goldberg to discuss the history of Biome, how linters and formatters work under the hood, what makes Biome's architecture fundamentally different from the tools it replaces, and what's coming next for the project and its community. This episode is hosted by Josh Goldberg, an independent full time open source developer. Josh works on projects in the TypeScript ecosystem, most notably TypeScript eSlint, a powerful static analysis toolset for JavaScript and TypeScript. He is also the author of the O'Reilly Learning TypeScript Book, a Microsoft MVP for Developer technologies, and a co founder of SquiggleConf, a conference for excellent web developer tooling. Find Josh on bluesky, Fostodon and dot com as Joshua Kgoldberg.
Josh Goldberg: Foreign. With me today is Emmanuel Stopa, open Source maintainer@cloudflare, creator of bio, and lead at Astro. Emma, welcome to Software Engineering Daily.
Emmanuel Stopa: Thank you for having me. Josh, how's it going?
Josh Goldberg: Things are good. I'm excited to talk to you. You've done quite a few interesting things in tech recently. You've been on Astro, you joined Cloudflare, you're a creator, lead maintainer of Biome. Before we get into all that, how did you get it to Koenigse?
Emmanuel Stopa: Well, uh, as uh, maybe the majority of the developers out there were like, I want to develop video games. Uh, so that's essentially why I got into coding. Things didn't plan as I thought they were. I went to university where they were supposed to teach, uh, game design. But in the year where I was supposed to join that class there was no professor. So I had to choose another class and eventually I haven't done anything around video games. So I ended up doing PHP postgres and all the stuff that web dev was at that time. And that's how I started. So then it was PHP developer Jquery and so on until like uh, React and all the cool kids that we have now.
Josh Goldberg: Do you have any emotions that come to mind when you think about developing front end full Stack apps in PHP and jQuery?
Emmanuel Stopa: Yes, because I see a lot of partners that I used to use back in the day coming up like ssr. Before it wasn't a thing like React developers and it was all about spas everywhere. So everyone was developing single page applications and that SSR came back because that's how you used to do things in php. So it was like, I mean there's nothing new here. We are just doing things as they were, just using JavaScript instead of, I don't know, PHP, C or Java. You know, at that time that's what we had. So it's kind of weird because like we are not inventing anything. We just, we are not reinventing the wheel. There's nothing exciting, you know, it's just the same patterns using different tools, different libraries. I like the tools that we have now simplified the process Back in the day when uh, I wanted to do spas or islands for example, it was a mess. Now we know how to do these kind of things. The libraries allow ah, us to do that. So it's like thank God, now we can do things very quick.
Josh Goldberg: It's lovely that we've learned how to do the same proper techniques but with a lot cleaner syntax now. Which brings us to kind of a transition for you. You started off as a sort of standard developer working on apps, PHP, jQuery and so on. But at some point you transitioned to dev tooling and one of the earliest projects that you were associated with in that space that got a lot of interesting news was Roam. Can you tell us about how that came to be and what that is?
Emmanuel Stopa: Yeah. So Roam ROM Tools was a project that was supposed to be like only one tool for all your web projects. So having formatted, linting, um, bundling, testing everything in one single application or binary or whatever. And I really liked it, the mission behind it. In the past I always struggled to maintain a lot of these depth libraries such as formatters, linters, bundlers, plugins and ROM was like a breath of fresh air. And I was looking for an open source project to contribute to. So uh, yeah, I mean let's do it. That's how I joined the mission. Rome at that time was in Typescript and Eventually Roam got some funding, they opened the company and they joined as uh, employee of uh, the tool. That's essentially how I got there. But like my passion to open source came before also Roam. I was involved into webpack before that. Uh, I was part of the CLI team. And why? Because like I fought with webpack a lot of times, uh, in my working experience with, in all the companies where it worked and I became a kind of an expert. I uh, was also on stack overflow, answering questions and things like that. So I wanted to increase my knowledge around webpack. And that's how you do it. You just go into open source and you uh, learn stuff from the actual creators.
Josh Goldberg: How did you make that jump from learning about webpack to uh, contributing back to it or to helping others? It seems like kind of a scary cliff for a lot of people, a gap in difficulty levels.
Emmanuel Stopa: Yeah, it is, it is scary. But at the end like you just have to do it. It's like a leap of faith. So, and you come to understand that you can't know everything, so you have to make the peace with it and just say, I don't know this, I don't know that, but I have experience with this thing. So maybe that's your solution, maybe this is your other solution. So once you understand that you can know anything and you have to accept that others might have, the answer just gets easy. So eventually you just do stuff that you want to do and uh, you try to learn what you want.
Josh Goldberg: And for you that's been simplifying those complex tech stacks you've mentioned. Is this something a little easier to wrangle?
Emmanuel Stopa: Yes, yes, exactly. Before tooling I was in frontend and it's a completely different world. Tooling requires a lot of different knowledge from uh, front end. But there are some similarities. There are some lessons that you can take from front end and where there's accessibility, error handling and fighting with browsers, fighting with things that don't work in a lot of context, take them into your tooling and for example error handling, it's the same like uh, you have your user that does a mistake, you have to handle it. You have your backend that does something funky, you have to handle it. Same for tooling, you always have your user that inputs something via cli, for example, and you have to essentially provide some decent feedback. So it's a different context. But at the end it's a product, you have your users and you have to provide something good that they like. So it's not that scary. And Yeah, I mean in programming you always have the same problems, more or less different context, but at the end it's just about data. You get some data, uh, you have to parse them and then uh, do something with it. And if there's a work, you just send a good feedback. If it does, you send the feedback that the user wanted.
Josh Goldberg: Functional programmers may be pleased to hear that everything ends up turning into a function that returns one of two types.
Emmanuel Stopa: Exactly.
Josh Goldberg: Let's talk about that doing something with it because you've worked on several projects now that do something with code that build it. So at the very barest before we go into the details, what is a builder or what is a bundler?
Emmanuel Stopa: Oh well, bundler what it is. Well as you said, like a bundle is a linker. So it's like taking different files and just create something that is linked all together. In modern programming now in the web ecosystem we have a bundler that has to take a lot of JavaScript files scattered in your application and dependencies and eventually creating something that it's pleasible to use in the browser for you as a developer and but especially for users, your end users. So you have to ship something that doesn't break, have to ship something that doesn't. Takes a lot to download for example. So you can't ship all like a uh, file of your old dependencies. Otherwise it's like megs and megs of JavaScript that your user needs to download and I mean a test studio also with lot of different things like HTML, css, sass, less typescript, coffeescript wasm now and a lot of stuff. So a bundler nowadays is actually from my point of view one of the most difficult and rewarding software that you, you can create or contribute to because there's a, there's a lot of to care and I think it's like, it's a. You learn a lot if you anyone wants to work on it because there's a lot of uh, going also source maps as well.
Josh Goldberg: So yeah, there's a lot going on there. Let's say that I have just the most barest of applications that uses imports and exports. I got an HTML page, a JavaScript file that imports from a couple of node modules, maybe another JavaScript file that imports that one and calls it and I want to turn that into some.com website and I'm going to use a tool to do that. First of all, do I need to use a tool in what situations can I if any get away without that?
Emmanuel Stopa: Well, you could use a Tool, but also you can't. It depends on your taste. Like back in the day with PHP and these kind of things like uh, you didn't need to, you just have your PHP file, it means your JavaScript and everything. So you had everything out of the box. Now things got more complex. Our users need more, the browser has more capabilities like we are recording our session on a browser, something that we couldn't do 10 years or 15 years ago. So capabilities increased. We have more tools at our disposal. So even the applications got complex based on what we want to shift. So eventually you want to use a tool like it simplifies a lot of boilerplate, like setting up the page or themes or even JavaScript doing interactions and things like that. You could do it yourself, but there's a lot of going on nowadays, so you don't want to do it and you want to focus on uh, your app, you don't want to focus on the boilerplate. So yes, nowadays you should use a tool that simplifies all the basics and so you can focus on creating whatever you want on the browser or even Electron where you have your native app. So you see the capabilities increase. We have endless possibilities.
Josh Goldberg: All right, you've convinced me. For my HTML and a couple of three JavaScript files page, I know it will get more complicated so I will use a builder or bundler. How does that actually work? How do we go from that source code split across different JavaScript files to something that gets run by users with all those optimizations you talked about?
Emmanuel Stopa: That's a really interesting question. I don't have a clear answer but like uh, as a uh, developer of some tools that do the kind of things, such as Astro, how does it work? So you have a concept of pages which are essentially your entry points where your user lands. Okay. And from there you essentially start building your tree of uh, dependencies which are styles, CSS files, components, JavaScript files, anything that your page requires. And that's how your bundler works. So you have your entry points where your user needs to interact, call them pages. So in most of the cases are synonymous entry points or pages. And there uh, your bundler creates a tree of dependencies of assets, essentially what it needs to ship in order to render and make the page functional. Of course there are a lot of uh, challenges like understanding the CSS files. Nowadays things got more complex because styles in some applications are shipped together with some components. So they are like atomic, like uh, take for instance Views, Belt and Astro. They have the council of components, single file components and each file component can contain a piece of JavaScript, can contain a piece of HTML and a piece of styling. So when you have multiple components that are uh inside the tree, you also need to understand the order of how this style needs to be bundled together in order to actually not mangle the end result. Like you could have your button that is imported in the middle of the tree or in the end of the tree and then you have to decide okay now what's the order? And that's what the bundler does. So is responsible to tackle this kind of problems for you so you don't need to fight them. And of course bugs can be there, but that's what the bundler does for you and same for JavaScript. So you have a lot of scripts important in your tree. You have to make sure that they are imported and executed in order. So eventually your button uh reacts to a uh form submit or it reacts to an error in your form without breaking other uh scripts. So that's I think like the bundler works
Narrator: in m Mobile application security good enough is a risk Guard Square uses advanced multi layered code hardening techniques and automated runtime application self protection and mobile application security testing combined with real time threat monitoring to deliver the highest level of mobile app security. Discover how Guard Square brings all these together to provide mobile app security for your Android and iOS apps without compromise at uh www.guardsquare.com if you're running postgres
Josh Goldberg: in production, you've probably felt the moment analytical queries start fighting your transactional workload. Most teams end up adding a second database and all the pipeline complexity that comes with it. Tiger Data, creators of TimeScaleDB, takes a different approach. We extend postgres with hybrid row and columnar storage, so one table handles both writes and analytical scans. Native compression cuts storage costs up to 95%. Continuous aggregates keep dashboards live without bash jobs, and it scales to petabytes without you re architecting. Companies like Cloudflare, Octave Energy, Schneider, Axpo and Flowco run production workloads on Tiger data today. No stale data, no second system to operate, just postgres managed for you. Ready for the workload you're building toward. Try it free@tigerdata.com Most AI frameworks started
Narrator: with voice and bolted on video as an afterthought vision Agents by Stream was built video first from day one. It's an open source Python framework that lets you build real time voice and video AI agents in minutes, not months, with 25 integrations for models like OpenAI Gemini and Claude sub 500 millisecond latency on Stream's global edge network and support for YOLO, roboflow and custom CV models. You get a production ready stack without the infrastructure headache. Whether you're building coaching tools, multimodal assistance or real time security pipelines, Vision Agents handles the hard parts. Get started free at uh, VisionAgents AI
Josh Goldberg: it's interesting the way that you describe the assets because very little if anything in your explanation is specific to JavaScript files. So let's say that we have a new kind of asset. Let's say I want to import some webp image and then use it as a source string in my file in this system. Does that mean that I could have sort of arbitrary extensible plugins for different sorts of assets?
Emmanuel Stopa: Yeah, technically yes if the bundler allows you to do so. But essentially a bundler needs to work in a very abstract way. But then yes to has specialized section where it needs to understand what is actually processing so CSS files, images which have different extensions or different kind of encoding and things like that. We have WASM which uh, also requires its own instantiation and other things. We have fonts for example. That's another asset that needs to be treated in a certain way. So yeah, I mean nowadays we are creating bundlers that uh, has to be designed in a generic way and extensible so users can extend the bandware for their needs. Because not everyone needs to deal with web images or avif or videos for example. There's also this kind of asset. So in the wild now we're creating since webpack area or rollup, uh, we are creating bundlers that are generic and users can extend it. So we are setting on a plugin system where users can essentially do whatever they want with the bundler.
Josh Goldberg: That users can do whatever they want yields a lot of power for users. But a lot of long lasting web developers may remember that power comes with a cost. Let's talk about two of those costs here. Performance and configurability or ease of use. There are horror stories out there of multi, uh, thousand line webpack configs that are slow. What would your response to that be?
Emmanuel Stopa: So my, let's call it belief or opinions on plugins have shifted a lot recently, especially now that I'm dealing with Biome which is built with a native language and Astro which is completely different uses plugins. So as you said there's a cost and I think uh, people shouldn't pay that cost. Like you have a lot of extensibility but yes, as hacker. That's nice. You do your project weekend, you can create your plugin and you have a sense of power, like you're doing something great because you recreating stuff. But then there's the other side of the coin which is you are at work, you are responsible of maintaining the product of your employer and that's the cost you pay. You have a lot of plugins, you have a lot of extension integrations that you have to deal with and they have a cost on your application. Sure. Then the bundler somehow has to be responsible of it and uh, reduce the performance and make it faster. But at certain point I think it's not responsibility of the bundler of the tool, uh, the plugin system anymore, it's responsibility of the maintainers of the plugin at eventually. Who pays the cost? The users. So I'm coming to a realization that we need the plugin systems just for certain things. Other things shouldn't be extended too much, but shouldn't be extended baked into the tool. So like it can do it correctly, uh, can monitor the performance but like we can give to our users all these integrations and plugins and eventually the performance of the tool degrades and you ended up with web part that takes like 30 minutes to bundle your application. So I don't know like we're trying to, and we keep trying to solve this problem. Like we have rollup but now we have roll down that wants to fix it by using a different language or maybe a different architecture. But I think it's not going to solve everything because like uh, applications are going to be more powerful, demanding and bigger because that's how the technology works. So we are going to see maybe in uh, three, four years, five years we're going to see again the same problems and we're going to try to solve them the same way. So I came to realization now maybe we have to do something different. So that's why configurations should be static, it shouldn't be dynamic. Like uh, they should be predictable. In fact, like I know Eslint paid uh, this cost and that's when V9 shifted their configuration to be flat. So like it's easily debuggable. Eventually they couldn't understand like which plugin was making a mess because it was all a recursion. Like uh, it was difficult to debug. And so they came to realization we have to do something. They broke the ecosystem. But I think it was something that had to be done because as a open source maintainer I understand where they were coming from and why they did it. Of course a lot of users were not happy, but I mean, they made a mistake, they had to fix it. Some, um, users were not happy, but in the long run I think it's going to pay off.
Josh Goldberg: How do you know or how are you able to tell where that balance needs to be drawn between power for users and comprehensive built ins?
Emmanuel Stopa: I don't have an answer for that, to be honest. It's very difficult to draw a line there. I think it's also a matter of trial and error. Like, okay, you can be uh, very extensible. So to be honest, I don't know. I really don't know. A plugin system allows you to do everything, but if you give it too much, you end up breaking stuff. You end up that you can do a lot of optimizations that you could do if your plugin system was more like tight or has less feature. To give you an example, like, eslint is a great plugin system and we have plugins everywhere, but it comes at the cost where they can't innovate. Now the force of eslint comes from its plugin system, but now they can't innovate, they can't try new things because otherwise all these plugins they could break, they could degrade without knowing. So that's kind of the line, like you should try to give enough power to please your developers and users, but not as much so that you can't innovate like you are a programmer. So as a programmer you also want to look for new things, try new things, because that's I think one of our passions. And if you can't try new things, what's the point? Like at the end it just doing maintenance and I don't know, it gets boring. So maybe that's why, uh, you ended up with creating new projects and trying new things.
Josh Goldberg: Yeah, that was a natural cycle where once a project gets successful that bogs it down. I want to talk a little bit about one of the major new things that a lot of projects, including Rome and Biome and Astro are, which is native speed code. You led the conversion from Rome in Typescript to Rome in Rust. First of all, why Rust? For those who haven't heard this hullabaloo, why are so many projects switching to specifically Rust, or at least native in general?
Emmanuel Stopa: Why Rust? So I think like there are two main reasons, or maybe three. Let's list them, then we'll count them. So first one, it's a really strict language. So when you have A dependency, there's less risk to break it. So like it's so tight the system that even like when you have a major, you have uh, less breaking changes or if you have them, you catch them straight away at uh, compile time. So it gives you the safety of having a lot of dependencies, but at least they break less often as it could happen uh, in TypeScript or JavaScript so you have less maintenance burden in your tooling. Second was essentially speed. Like Rome when it was in Typescript was actually great but it suffered from a lot of memory consumption. So at that time ROM was able to bundle itself. So it was um, like as a binary could bundle itself. And while it was doing that was consuming a lot of memory, like 8 gigs of memory. It wasn't sustainable. Like uh, it felt like it reached the limit of node js. So that's when we decide, okay, maybe we have to go somewhere else. You can try to do a lot of optimizations, but if you can't leverage the actual memory, like yes, JavaScript has some tooling for garbage collection, but it's very, very limited. Rust as a native language allows you to manage your memory way more than JavaScript. And third point is how easy is to integrate with wasm. So like uh, Rust has a native bindings, uh, using the WASM bindgen crate. So it's very easy to have your Rust code and porting into wasm so then it can be shipped into browsers, other languages that are able to, to interpret WASM and they execute it. That's really great for like a uh, playground and things like that. So I think that's one of the reasons because like sure the language is very typed, but even TypeScript is typed in a different way so it wasn't the problem. And Rust has gained a lot of traction recently for their uh, memory safety. So you don't need to deal directly with memory like C or C or other similar languages because Rustic does it for you using their Borrow Checker. So it takes a while to get used to but it's the language that does it for you, so you don't need to take care about that part so you can focus on your application.
Josh Goldberg: That sounds great. Let's jump forward in time a little bit. Rome was around the 2021, 2022 era. How did we get from Rome to Biome and what is the difference between those two projects?
Emmanuel Stopa: Yeah, so for a year and a half we were good at Rome, we were doing great. But eventually the company behind it went under so they couldn't get any more money. So eventually they had to close. Thing is I liked the project. Like I joined the open source project before getting hired and they wanted to continue it. So even after I left the company and I joined another company, I continue to contribute to Rome. Other people joined so I wasn't the only one anymore. So eventually we had a team of volunteers and we shipped. We continue shipping eventually. Like I really wanted to change the face of the project but it always requires a lot of work, you know like logo names, website domains. So you don't want to do that. You know you want to. It's a uh, it's really annoying. But eventually we had to do it because the NPM tokens expired so we couldn't actually ship and publish new versions on NPM anymore. So we were actually forced to do the move. And why buy them? So like James, which was the CTO at ROM at that time, had this idea in case we wanted to change Rome to call it the second rom. So second ROM M Biome. That was the idea. So I asked him m can I use it? Are you okay with that? Yeah, sure, go ahead. And uh, yeah. And eventually so Rome fell in December and in August of the next year we announced Biome as the new rom. I would say the mission changed slightly because we are not focusing on the bundle for example because we have less resources, we don't have people dedicated to the project. So we are now focusing on formattery linter because that's what we had. So instead of going horizontally we went vertically. So like we ship more features into the linter and the formatter so more languages but still like more read throughs formatting capabilities. But like we are not focusing at the moment in the bundler or the testing suite, uh, stuff like that. So and I think we're happy with that. We are doing still great things.
Josh Goldberg: So yeah, let's talk about those great things. Most users I've talked to are not extremely familiar with formatting and linting as concerns. They know that they clean up the code base. Maybe they know that linting does more logic formatting more well formatting white space. What does Biome do for users around formatting in linters?
Emmanuel Stopa: So first of all it creates like uh, it wants to ship a different developer experience compared to the tools that we have. So a better messages, something that you can actually action you have your error and Bayern tells you okay, that's how you should do it or you shouldn't do it. So some users, yes they dismiss the linters as like a Nice to have. So what we're trying to do is also to teach people how to do stuff. Like, uh, we ship this lint rule that targets the dot reduce function of, uh, JavaScript and says to not use the spread operator when you return the accumulator. And the lint rule tells you don't do it because it's a performance problem. And I've seen people that didn't know that. And once they know the rule, they learned something. So that's one, uh, of the missions. Like we have a linter that teaches you something because as I told you before, not everyone knows everything. So if we get the chance to teach you something, I think we did good. So we're spreading the knowledge. So that's why our lint rules have to have a really high standard. They have to tell you why it's an error. Because if you're not able to tell why an error exists, then it's not an error, it's a moot point. And then like, uh, for Martin, he wants to just provide a faster experience compared to the tools that we had at that time. Like, I know that users in the past were kind of unsatisfied with Prettier's performance, which was at that time the only widespread formatter in the JavaScript world and the web world. So with Biome we provide a very similar formatting, but at least it's faster, especially in CIs and things like that. But we also like want to provide an experience that is tied also to other tools. Like, uh, Biome knows your gitmuir files, for example, so you just hook into them and it doesn't format the files that I ignored in Git. You can also integrate it with your editor config, for example. So you have your editor config, so you don't need to maintain the Biome config, you just use what you already have. So it's not just about linting and formatting, but we also like embrace the other tools so that Biome gets to know what you're using and you learn from them. We're doing the same with Svelte Vue Astro CSS modules. Tailwind too. So seems like a web dev is quite vast. Uh, we don't want to limit ourselves to just one tool, but we think we should actually embrace a lot of them so users get to know them and you learn something that you might not know.
Josh Goldberg: You've touched on one of the really lovely parts of using Biome, which is, as you said, it's all in There you can run the format the linter just from one command. How much simpler is it in your experience to configure Biome compared to how things were configured say five years ago?
Emmanuel Stopa: So I think it's actually really good and fast because you don't lose a lot of time. I still remember when I used to set up eslint and Prettier years ago and it got easier. But like the fact that you have to install three or four packages and then you have to configure ESLint to use pre tiers config or plugin, I don't remember. So was a nightmare. I mean sure it takes uh, 10 minutes, but why you have to do that? I mean you shouldn't spend so much time on these tools and that's why Biome is there. Like you have one config with sensible defaults, which means that you just install the dependency and that's it. You don't need to do anything else. You just use it. If you don't like the defaults, okay, just you can run uh, bio in it and change the defaults and that's it. Also, you don't need to format the code that is fixed by your linter because it's all in there. Mayoon does it for you and it works out of the box in your editor. So what you get in the cli, you get it as well in your editor. You don't need to do anything like uh, anything at all. Instead you can install the extension, of course, but other than that you don't need to install true instructions like Prettier or eslint. You don't need to modify any configuration. It's all in there. Works out of the box most of the times, of course. So you see users spend less time in tooling, setting up their tooling so they can do programming as they want. Because that's what we like to do. We don't like to set up tooling.
Josh Goldberg: Absolutely. Diving into the tooling a bit. Formatting has not changed significantly over the last few years. Other than what the defaults may be or configuration, the architecture has been pretty stable. Linting, on the other hand, Biome does linting things quite a bit differently than say eslint that came before. What's different about a Biome lint rule versus say, uh, a predecessor ESLINT rule?
Emmanuel Stopa: Okay, so one thing that we recently shipped in Biome, um, type aware rules and project rules. So we know that we have TypeScript Eslint. Thank you Josh for what you shipped to us the existence of the Eslint that leverage TypeScript so they provide useful rules such as non floating promises or nomi used uh promises. But I know that this kind of plugins need to do something that eslint can't provide, such as scanning the whole project or the whole dependencies. Because these kind of rules need to understand not just the file that you have open on your editor, but they have to resolve types uh, dependencies. So they need to do a lot of work in order to work. And that's something that eslint doesn't provide out of the box, but biome does. So Biome in this case is able to scan your old project before starting the actual linting is able to collect a bunch of information so that we can provide powerful intros such as no import cycles. So is able to fly over all the import tree of your project and understand if you're actually importing the same you're doing a cycle is able to scan your dependencies so it understands if you're using a dependency that is not installed in your package. Isn't one thing that for example I recently merged is a uh, lint rule that is able to understand if you're using a uh, CSS class that is not defined anywhere. So a biome is able to scan the whole project, CS files, jarstri files, view files, all the files, it collects all the information and then it does the lint rule that inspects, I don't know, your component, your div or whatever, your element. It reads the classes that you used and it checks if they're actually defined somewhere in your project. And if they are not, this says oops, you're using a CSS class that it's not defined anywhere. And it's also able to show you the actual tree of components that they were analyzed. And that's something that is provided by the bio module graph, which is a language agnostic in a sense like uh, is able to collect multiple languages or files or assets in the same time like uh, HTML, CSS, JavaScript and so on. And I'm really proud of what they've done because it's something that like the tools that we have today, they are not able to do that or I mean that I'm aware of of course. So that's what Biome is able to provide that the current tools might lack or they don't provide out of the box.
Josh Goldberg: You've mentioned two big features now there's type lint rules out of the box and then there's the biome module graph, talking about type lint rules a little bit. How does that type information work in Biome?
Emmanuel Stopa: Yeah, so in Biome, um, we try to do things differently because that's essentially our way of doing things like providing something different from what you have so you can try it. So Biome, um, does something called type inference. So it actually tries to collect and infer, as it says, the types of your code, like of the JavaScript TypeScript files. So the project and the efforts were led by another core contributor and Vercello actually employed the contributor to actually ship the feature. So it was a great community effort and it required the uh, a lot of resources and time. But now we are able to ship lint rows that don't require the actual TypeScript compiler. So you don't need TypeScript to understand if you are using incorrectly a promise. There's a dangling promise that you haven't awaited. How does it work? Well essentially the engine relies heavily on the model graph in order to essentially collect and read all the files that the project uses, as well as um, the dependencies. So it's not just the project, but also all the libraries involved in the application. And then there's a lot of work where it tries to flatten, for example expressions functions. I don't know all the details because the efforts were led by another co member, but I managed to actually fix a couple of bugs there because the engine requires a lot of tools such as not just the model graph but also the semantic model. So just the other day I fixed a bug where biome couldn't infer the type of dependency. So there was import function from Lodash for example and he couldn't understand if it was a promise or not. So and I fixed it the other day by integrating the semantic model into the inference system M or I was able to ship these other rule called not necessary conditions, which tells you, oh, uh, you don't need to do this kind of check because it's always true. Like you have a variable that is always true. So it tries to infer when, for example it changes value and things like that. And at the end when there's the if or whatever it tells you, oh, there's no need to do any check because this variable never changes, it's always true. So hopefully it answers your question very much.
Josh Goldberg: So you've mentioned another type of graph now, semantic graph. What's the difference between a semantic graph and a module graph?
Emmanuel Stopa: So uh, it's not called semantic graph, but it's called semantic model. So the Model graph is just essentially a data structure that just checks, okay, so this module, so this file is imported by this other file and so on. So it's very generic. It tells you what imports, what exports and there it is, nothing else. Semantic model is actually more specialized. It's not aware of other files, it's just aware of one file and it's very specialized to the kind of file. So in JavaScript it specializes into the understanding, uh, the various scopes inside a file. So you have your global scope, you have scopes inside the functions, then you have your arrow function that don't have scopes. So you have your classes, they have a different scope. So that's what this semantic model does. Uh, for example, it checks as well if a binding is exported or not. So it does very specialized things. For css, for example, it focuses on calculating the specificity of your classes. So as you can see it's very tied to the implied semantics of the language that you're handling. Surely we're going to have for example a semantic model for GraphQL. I don't know the language. Other maintainers have more expertise than me, but they know they're going to use it, they're going to create it so they can provide spatialized ring tools. The model graph is just a big pile of data of all your files that you have. It's basically a trio and branches and leaves and you have your edges, you know how they are connected to each other. So it's mostly like a spider web and you have to navigate it to understand, to collect the information that you need.
Josh Goldberg: One of the difficulties with building lint rules specifically in native speed code is that many of the end users aren't native speed developers. What are you in Biome doing to solve that uh, developer interoperability difficulty to.
Emmanuel Stopa: Well, I mean as we mentioned, like Biome has a plugin system to try to bridge the gap as a plugin system based on this DSL called GridQL. So it was chosen some time ago as a, uh, winner after a lot of discussion. So we are aware that we can do everything and there are some requirements that are uh, project specific. So things like that belong to your ARC or to your employer, to your code base. So that's where we think a plugin is actually very useful because also like your sensitivity, uh, things like that. So we have your, this powerful DSL that biometric, um, is able to interpret and it has its own runtime. So with these plugins users are able to inspect the code and just to let you know, so until now these plugins were not able to provide, uh, code fixes. So until now it was just, that's the rule, that's the diagnostic, there's the error, and that's it. So we have now a PR that is able to actually provide a code fix. So probably in the next minor user will be able to create an intrule that is able to autofix possible issues in their code base. So this actually gives my point where the plugins are bad, but I think in this case are actually valid because a tool cannot know everything and it shouldn't. Like I, uh, shouldn't know about the quirks of your code base because they are sensitive data. And that's where a plugin makes sense. You leverage the tool, uh, Biome, eslint, oxe, whatever, and you apply to your code base specifically to your needs because they belong to your project.
Josh Goldberg: So it sounds like you could use code fixes from Lint Rules as a sort of code mod tool.
Emmanuel Stopa: Yes, yes, exactly.
Josh Goldberg: Love to hear that. That's really cool though. So there's already a Biome search command and just looking through the biomejs.dev ref, it looks like you can do some pretty powerful matches with not that much syntax with GridQL. Have you seen a lot of developers pick this up and use it?
Emmanuel Stopa: So I'm not into uh, a lot of this part of the tooling. I know that there are users that have like 70 or more biome plugins written in GridQL. So I feel like there are users that actually leveraging the plugin system a lot. But yeah, like GridQL was born as uh, a code mod. That's why it's so powerful and that's why it has a lot of weird syntax. Because one of the initial objectives was to create code mods and essentially that's what Bayern could potentially do in the future. You could create your code mod to. I don't know, you have your react. Ah, from 1819. There's a lot of changes. You have your code mod or even internally. So you are changing stuff. There's a lot of refactor, create your plugin that does the code mod run Biome. Um, and there it is.
Josh Goldberg: Beautiful. Let's talk about the feature a little bit. What are some of the big flashy upcoming features around Biome that you're excited about?
Emmanuel Stopa: Oh, that's nice. Okay, so there's a lot going on, a lot of ideas. So one is this lint rule that I talked about that is able to catch uh, unused classes. It's still early stages because there's a lot of components and the ecosystem is big quirks. The second thing that we are working on is the watcher. So you can run Biome Lint watch and then you can start typing and biometric change. It links the new file that you just changed and it checks if there are some violations or not. And I think it also will work for the formatter. But I mean it's still in the early stages and the reason why we're able to do that is because Biome is already a watcher under the hood. So we are just exposing the watcher using the cli. One other thing that we're doing this is just third party contribution, so I'm not doing that much. So plugins that will be able to emit code fixes and they will be able also to set the severity. So until now users they couldn't do much. So now we are making plugins more powerful and customizable to our users. We are working towards markdown support. Um, so Internally we reached 100% coverage against CommonMark. This is also done by another third party contributor. So that's amazing. I'm just essentially reviewing PRs and contributing with them. So there's an effort at the moment doing a refactor of the parser while keeping the conformance to common mark to 100% and we are setting up the formatter uh, at the moment. So if everything goes well, it's going to be part of the next miner. Yeah, I think that, I mean there's also we're doing a lot of lint rules for review and also Svelte probably will going to start creating some lint rules now that we have a very good handle on this belt syntax. So now we can start shipping some lint rules for them for Astro. I still need to investigate. I know there's a eslint plugin for Astro, but I'm not familiar with the rules, so probably there's uh, room for implementing something there as well.
Josh Goldberg: It would be nice if the leader of the Astro project and the leader of the Biome project knew many of the same people together.
Emmanuel Stopa: Uh, ah, yes, which is me.
Josh Goldberg: Well, great. One of the interesting notes you brought up was editor support. Can you tell our users what is LSP and what does that mean in this context?
Emmanuel Stopa: Sure. So LSP stands for Language Server Protocol. As the acronym says, it's a protocol to essentially create an editor server that works in all editor clients. Nowadays the vast majority of editor clients support this protocol. So like Bscode, Z, Webstorm and all the Intellij, sorry, JetBrains, IDEs, Vim, Alex. So all of them now support LSP and this is actually quite powerful because we just need to develop the server in one place and the DX is the same in essentially all the editors. So one of the BIOS mission is to focus LSP ah as well. So to provide all in one experience, which means that we implement the business logic in one place and then you get the same look and feel on the cli, the LSP in the playground. So any client, uh, because Biome is essentially a server, you have multiple clients and that's what we do for robot diagnostics. So what you see in the CLI is the same thing that you see in your editor. So something that we could potentially do in Biome that other tools can do is to leverage the model graph to implement things like the goto. You have your uh, function, you want to know where it's defined, so you do command, click and it takes you to the definition. So that's something that Biome potentially could do. So there's uh, endless possibilities with Biome because everything is central, we own the stack, we own the information, but still it requires uh, essentially the time. So I'm setting up essentially the whole infrastructure. I have a lot of ideas, I just need the time to implement them. Now with these AI agents I get to do things quickly because they just write the code and they review it. So yeah, hopefully it answers your question.
Josh Goldberg: That does. Before we start to wrap up, are there any other big ticket features or fixes from Biome that you're excited about coming years?
Emmanuel Stopa: No, I really want to do a uh, shout out to the actual community because a lot of fixes, a lot of new features have been developed by other people that aren't the core team. So Biome is essentially a community effort. We are just essentially the orchestrators and the manager. But we are seeing a lot of people sending fixes, sending features. As I said, the markdown parser has been done by another person, the formatter as well. We are actually also working on CSS support, Sasso support. So yeah, I mean I want to do a shout out to all the contributors because like a lot of things that you're using and other people are using have been shipped and created by the community essentially.
Josh Goldberg: Let's talk about the community then. Biome's been around for a few years now. It's outlasted Rome, it's clearly sustained itself. How have you been able to build A community where so many open source projects aren't.
Emmanuel Stopa: Well, I think like Biome, um, as a concept uh, attracted a lot of people as I was. So that's just one of the reasons. Second, I don't know, I have some experience in open source, I'm involved in other communities. So I learn from the other communities and apply it to the biomes community. I try to be friendly every time. It's not easy and that's actually very difficult as a maintainer to keep your cool. And I know that sometimes uh, I wasn't able to. And also like you have to be active. Like we have our Discord chat and if you're able to answer questions as quickly as possible, people eventually acknowledge that and they like it. Uh, because sometimes you are in a project, you file an issue or you ask a question and then it's basically you don't get an answer for weeks. So I think like that's where I try to focus on quick feedback if I'm able to. And I think like this is paying off because users seeing that activity, they see that their problems are solved, their questions are answered or maybe we don't have ah, the answer but at least there is some discussion, you know, so there's a, uh, something moves. Every single time there's something to be
Josh Goldberg: said about positivity, you join the Biome discord and there are all these fun channels, there are lots of emojis, exciting announcements. It feels like a very big project and a fun place to be.
Emmanuel Stopa: Yeah, we try, we try to be active, to be positive, as you said, to communicate. That's also something that uh, since day one I wanted to do. If there's something about Biome, anything related, just share it. Uh, or even if it's not about Biome, share it. You know, you have a link that you like, uh, just drop it. And people like it because it's something nice to read. So that's essentially the mentality. You are there, you want to share something, do it. You are more than welcome to do so.
Josh Goldberg: Lovely. Let's say that I'm a listener with a large code base, complex formatting, linting and so on. How would I get started trying to switch things over or to evaluate to Biome.
Emmanuel Stopa: So Biome, um, has a couple of commands that allows you to read the config from ESLINT and prettier and create a biome config that matches as much as they can what you had before. Of course we don't have all the ESLINT rules, but at Least something. Second, you can actually do a uh, first pass of your linter by suppressing or the violations because you might have a lot of violations, your old code in the big code base. So you do biome lint suppress, suppress, reason and say migration or whatever and you're good to go. Maybe you can also turn off the formatter if you want. But like we match 97% of pretty s formatting, so you should be good to go. But at least the linting is there, it doesn't scream at you. And uh, you can keep your code base there and then you can progressively address lint rules as you go. That's essentially what you could do for your migration if you have a lot of formatting problems. One technique that I usually suggest is to have a PR make sure the CI is green, merge it and then goes with another PR that ignores the commit of formatting. So like your history is not mangled by the formatting. We do the same also in the biome repository. So when we have these trivial changes that don't bring anything to the table, you ignore that commit that hash so that your histories the blame. You know, when you do a blame of the file, it doesn't show any meaningless information.
Josh Goldberg: That's a great tip. Uh, you're talking about git revision ignoring.
Emmanuel Stopa: Yes, exactly. There's a git file where you essentially can list all the commits that you want to ignore and those commits won't appear in the history of your git blame.
Josh Goldberg: Great. Let's say that I have a new project and I want to get started fresh with Biome. How is that different?
Emmanuel Stopa: So you start Biome and you're good to go. You could run Biome initially, which bootstrap a biome config for you, which essentially mirrors our defaults. So it might be lengthy, but at least you can see what are our defaults. You don't need to go to the website. You can understand what's the default and then you can change it like tabs versus spaces, lint rules and so on. Other than that, we ship also a really nice tool called biomexplain from the CLI where you can just type biomexplain, um, no debugger and it shows you the docs right in the cli. So if you don't have any connection and you know the name of the Internet connection and you don't want to go to the website, you just type that command and you can see what their lint rule does for you.
Josh Goldberg: Speaking of which, that website is biomejs.dev yes, yes. Great. Are there any other resources or links you'd want to send people to if they wanted to learn more about Biome?
Emmanuel Stopa: I think the website is quite self explanatory. Also the main GitHub repo. It's also a nice resource and yeah we try to be central so we try to have everything in one place and the website is where everything goes and our discord. So biomejs.devchat and you should be good to go.
Josh Goldberg: Excellent. I like to end interviews with one non work question. You mentioned at the very beginning that you were interested in video games. What games are you playing these days?
Emmanuel Stopa: So at the moment I'm playing Assassin's Creed Shadows. I'm not a big fan of the whole saga but I like the last video games there because I'm really focused on role playing. So you have your character, you choose your skill that you want to develop, your weapons skills and things like that. So it's also in Japan which I really like. So it's a uh, really nice mix of things. I really like role playing, so GDR and things like that. RPG essentially. I'm not into like sports or shooting. I really like RPGs. Yeah, fun.
Josh Goldberg: Are there any lessons you've learned in programming that apply to uh, the stories of these video games or vice versa?
Emmanuel Stopa: If you want to learn how to do video games, you have to do it yourself. Just do it yourself, uh, like a lot of people do. Indie video games. That's how I think you should start. I mean I tried the university, it didn't pan out. Uh, so do it yourself. Uh, if you have the passion and the time. I don't have the time anymore, so that's the only problem. But if you have the time and the passion, do it yourself. I mean with the tools that we have nowadays, I think it's uh, quite easy to pick up.
Josh Goldberg: All uh, you need is time, interest and energy. Yes, well great. Emma, this has been wonderful. Thank you for walking us through your history and Biome and all the fun things around analyzing and linting that come with it. If people wanted to learn more about you specifically, where would you direct them to go on the Internet Friday I
Emmanuel Stopa: can go to my Bluesky account, Em Atypical XYZ and the GitHub account and yeah, I mean that's essentially where you can find me and where I'm active. I'm not a uh, real social person. I like to lurk and I engage less.
Josh Goldberg: Excellent. Well thank you for all the info. For software Engineering Daily. This has been Emma and Josh Goldberg. Cheers, everyone.
Emmanuel Stopa: Thanks.
Other episodes covering the same guests and topics, from across The B2B Podcast Index.