
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,
Loading summary
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 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 at Cloudflare, creator of Bio and lead at Astro. Emma, welcome to Software Engineering Daily.
Amanuela 'Emma' Stapa
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?
Amanuela 'Emma' Stapa
Well, as maybe the majority of the developers out there were like, I want to develop video games. 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 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 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?
Amanuela 'Emma' Stapa
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 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 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?
Amanuela 'Emma' Stapa
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, 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 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 employee of 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 I was part of the CLI team. And why? Because like I fought with webpack a lot of times in my working experience with in all the companies where it worked and I became a kind of an expert. I 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 learn stuff from the actual creators.
Josh Goldberg
How did you make that jump from learning about webpack to 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.
Amanuela 'Emma' Stapa
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 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?
Amanuela 'Emma' Stapa
Yes, yes, exactly. Before tooling, I was in frontend and it's a completely different world. Tooling requires a lot of different knowledge from 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 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, you have to parse them and then 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. Exactly. 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?
Amanuela 'Emma' Stapa
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 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 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?
Amanuela 'Emma' Stapa
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 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 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?
Amanuela 'Emma' Stapa
That's a really interesting question. I don't have a clear answer. But like, as a 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 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 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 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 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 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 reacts to a form submit or it reacts to an error in your form without breaking other scripts. So that's I think like the bundler works
Narrator
in 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 www.guardsquare.com if you're running postgres in
Sponsor
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 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?
Amanuela 'Emma' Stapa
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 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 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, 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 thousand line webpack configs that are slow. What would your response to that be?
Amanuela 'Emma' Stapa
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 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 reduce the performance and make it faster. But at certain point I think it's not responsibility of the bundler of the tool, 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, 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 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 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 they should be predictable. In fact, like I know Eslint paid 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 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 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?
Amanuela 'Emma' Stapa
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 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 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, why Rust?
Amanuela 'Emma' Stapa
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 less breaking changes, or if you have them, you catch them straight away at 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 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 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 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 Rust has a native bindings 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 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 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?
Amanuela 'Emma' Stapa
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. 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 Biome, that was the idea. So I asked him, can I use it? Are you okay with that? Yeah, sure, go ahead. And 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, 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?
Amanuela 'Emma' Stapa
So first of all it creates like 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 we ship this lint rule that targets the dot reduce function of 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 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, 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 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. 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.
Amanuela 'Emma' Stapa
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 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 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 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 a predecessor eslint rule?
Amanuela 'Emma' Stapa
Okay, so one thing that we recently shipped in Biome 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 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, 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 lint rule that is able to understand if you're using a 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 is able to collect multiple languages or files or assets in the same time, like 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?
Amanuela 'Emma' Stapa
Yeah, so in Biome 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 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 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 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. Or I was able to ship these other rule called not necessary conditions, which tells you, oh, 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?
Amanuela 'Emma' Stapa
So 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 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. 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 developer interoperability difficulty to?
Amanuela 'Emma' Stapa
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 winner after a lot of discussion. So we are aware that we can do everything and there are some requirements that are 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, things like that. So we have your this powerful DSL that biometric 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 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 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 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.
Amanuela 'Emma' Stapa
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?
Amanuela 'Emma' Stapa
So I'm not into 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 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 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. 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?
Amanuela 'Emma' Stapa
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 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. 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 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 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.
Amanuela 'Emma' Stapa
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?
Amanuela 'Emma' Stapa
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 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 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 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 endless possibilities with Biome because everything is central. We own the stack, we own the information, but still it requires 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?
Amanuela 'Emma' Stapa
No, I really want to do a 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?
Amanuela 'Emma' Stapa
Well, I think like, Biome as a concept 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 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 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 the answer, but at least there is some discussion, you know, so there's a. Something moves every single time.
Josh Goldberg
There's something to be 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.
Amanuela 'Emma' Stapa
Yeah, we try, we try to be active, to be positive, as you said, to communicate. That's also something that since day one, I wanted to do. If there's something about Biome, anything related, just share it, or even if it's not about Biome, share it. You know, you have a link that you like, 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?
Amanuela 'Emma' Stapa
So Biome 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 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 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. You're talking about git revision ignoring.
Amanuela 'Emma' Stapa
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?
Amanuela 'Emma' Stapa
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 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.
Amanuela 'Emma' Stapa
Yes.
Josh Goldberg
Great. Are there any other resources or links you'd want to send people to if they wanted to learn more about Biome?
Amanuela 'Emma' Stapa
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?
Amanuela 'Emma' Stapa
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 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.
Josh Goldberg
Fun. Are there any lessons you've learned in programming that apply to the stories of these video games or vice versa?
Amanuela 'Emma' Stapa
If you want to learn how to do video games, you have to do it yourself. Just do it yourself 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. So do it yourself 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 quite easy to pick up.
Josh Goldberg
All 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?
Amanuela 'Emma' Stapa
Friday I 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 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.
Amanuela 'Emma' Stapa
Thanks.
June 18, 2026
Host: Josh Goldberg
Guest: Amanuela “Emma” Stapa, Senior Systems Engineer at Cloudflare, Lead at Astro, Creator/Maintainer of Biome
This episode features a deep dive into Biome, a modern open-source toolchain for web projects, with creator Emma Stapa. Biome is designed as a fast, opinionated, Rust-based replacement for both Prettier and ESLint, offering unified formatting and linting with minimal configuration. Josh and Emma discuss Biome’s origins, its technical evolution from the Rome project, modern JavaScript tooling challenges, transformative features (including its module graph and type-aware linting), and community-driven development.
biome lint watch for real-time feedback as you type.biome explain) helps new users get started quickly.biomejs.dev/chat).Migration:
biome explain <rule> for inline documentation.Greenfield:
biome init for defaults and docs in config.Biome represents a new class of JavaScript tooling: Rust-powered, cross-file aware, deeply integrated, and committed to both speed and user experience. The project’s success is rooted in a passionate, welcoming community that continues to innovate collaboratively. Whether converting legacy projects or starting new ones, Biome’s default-driven simplicity, rich plugin capabilities, and educational linting aim to raise the bar for sustainable, joyful web development.