Announced on April 16 at RubyKaigi 2025 in Matsuyama, Japan.
Today at RubyKaigi 2025, I’m excited to introduce a project I’ve been heavily focusing over the last few months:
🌿 Herb — a fast, modern, and HTML-aware ERB parser, designed from the ground up for developer tooling.
Why Herb?
As web development in Ruby evolves - especially with the rise of Hotwire and HTML-over-the-wire patterns - it’s become clear that traditional ERB tooling hasn’t kept up.
Rails has always been a joy to work with and always stood out in it’s developer experience and always had a strong view layer, centered around ERB templates.
With the introduction of Hotwire and HTML-over-the-wire becoming the default in Rails 7+, we’re writing more HTML+ERB than ever
Herb is designed to bridge that gap. It brings real-time, editor-friendly parsing capabilities to ERB, enabling a wave of new tools like formatters, linters, and language server integrations (LSPs).
Herb is fast, fault-tolerant, and deeply aware of the HTML structure. It’s built for developers and tooling developers who want precise, reliable tooling without compromise.
Even as Ruby developer tools have improved — thanks to projects like Shopify’s Ruby LSP and Prism — view files have largely been left behind. HTML embedded in .html.erb
files remains a black box:
- No (or limited) jump-to-definition for view helpers
- No way of understanding the HTML semantics in view files.
- No syntax-aware formatting or linting
- No way to understand what ActionView’s
form_with
,link_to
, orrender
will output - No editor support for HTML-aware ERB analysis or transformation
In the 2024 Rails Developer Survey Stimulus climbed to the number one spot in the JavaScript frameworks sections.
This is especially limiting for modern Rails apps, where Stimulus, Turbo, and Hotwire all rely heavily on writing rich HTML on the server.
A Parser Built for Tooling
That’s where Herb comes in.
Herb is a new parser written in C, purpose-built to understand interleaved HTML and ERB. It gives tools the ability to reason about HTML structures even when they’re dynamically generated with Ruby helpers and nested in ERB tags.
Herb is:
- HTML-aware, with a purpose-built lexer and parser
- ERB-aware, with integration points to Ruby’s official Prism parser
- Error-tolerant, to support real-world code and in-editor feedback
- Whitespace- and structure-preserving, critical for formatters and linters
- Built for speed, enabling real-time updates in developer tools
- Designed to be embeddable, with bindings for Ruby, JavaScript, and more
Herb produces a full AST representing the structure of HTML + ERB templates, making it ideal for:
- Building ERB-aware formatters and linters
- Writing intelligent LSP features (e.g. autocomplete inside ERB)
- Performing static analysis on server-rendered markup
- Refactoring or transforming views at scale
- Highlighting issues with tag mismatches or invalid nesting
Why Not Nokogiri?
You might ask: why not just use Nokogiri?
Nokogiri is great for working with HTML — but it’s an HTML-compliant parser. That means it fixes your mistakes (autocloses tags, moves nodes around) and doesn’t preserve exactly what’s written in your .html.erb
files. That’s how it’s intended to work and what you would expected from a HTML5 parser.
Don’t get me wrong, Nokogiri is an awesome tool and is perfect when trying to parse HTML as browsers would, but it sadly doesn’t work great for developer tooling.
With Herb, what you parse is exactly what you wrote. No assumptions. No transformations. Just the raw, structured syntax tree of your view template — including whitespace, comments, and malformed fragments.
This allows us to exactly see what you’ve written in your view files and allows us analyze the source as it it is. This also allows use to write tools like formatters and linters to annotate the view files with diagnostics to help you find syntax or semantic errors.
What’s Next
Today is just the beginning as with the release of the parser we now have the foundation to build more advanced tools.
For now, Herb focused on empowering developer tools: LSPs, linters, formatters, analyzers, refactoring tools — the kind of tools we’ve long had in other ecosystems, but that Ruby, and HTML+ERB specifically, has lacked in the view layer.
Now with this parser released, we are looking to improve existing tools in our ecosystem, including:
and possibly more!
Getting Started
Ruby
Herb is bundled and packaged up as a precompiled RubyGem and available to be installed from RubyGems.org.
Add gem "herb"
to your Gemfile
and call Herb.parse_file()
to get started.
require "herb" Herb.parse_file("path/to/view.html.erb")
Check out the Ruby bindings documentation to learn more.
JavaScript
We are also shipping two NPM packages for the use in Node.js and a WebAssembly build for the use in the browser. You can install the @herb-tools/browser
or @herb-tools/node
package from NPM respectively.
Check out the JavaScript bindings documentation to learn more.
Playground
We also have an interactive browser-based parser playground to explore how the parser works.
The playground uses the @herb-tools/browser
and WebAssembly build to run the parser fully in the browser.
Check out the interactive playground to play with the parser output yourself.
Summary
For my RubyKaigi talk I prepared a summary slide. Here is the most important information from this talk on one slide:
A Gateway to Better Tooling
Herb isn’t just a parser - it’s a foundation for better HTML Templating Tooling. A better HTML+ERB Syntax Tree, better HTML+ERB editor support, and meant to level up the developer experience across the board.
Whether you’re building modern Rails apps or maintaining legacy templates, Herb will bring clarity, structure, and modern ergonomics to your HTML+ERB views.
I’m excited to share this with the Ruby community today and look forward to seeing how you use it.
→ View the documentation
→ Try the playground
→ GitHub repo
I’m planning to write more about Herb in the next few weeks to touch on the technical details, architecture, design-decisions, differences and more!
Let’s build the tooling the modern Rails view layer deserves. 🌿
— Marco
Code blocks highlighted by Torchlight.