Jb: a JSON template that is just a Ruby method returning a Hash
A simple and fast JSON API template engine for Ruby on Rails
At a glance
- What is it?
- Jb is an alternative to Jbuilder for Rails that drops the builder DSL entirely: a .jb template is Ruby code returning any object that responds to to_json, rendered through Action View like any other template. The speed argument is concrete, since Jbuilder re-finds the template for every element of a collection while Jb resolves it once.
- Who is it for?
- Jb fits a Rails codebase that finds Jbuilder's DSL heavier than the problem, especially where responses are assembled from collections, since the library does the same work with plain Ruby and a smaller API surface. Skip it if your team has invested in Jbuilder templates, or if you want a DSL that constrains structure, since jb deliberately has no original builder syntax and leaves composition to Ruby.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The template is a Ruby method, not a DSL
The syntax section is one sentence and it is the whole idea: a .jb template should contain Ruby code that returns any Ruby Object that responds_to to_json, generally a Hash or Array, and that return value is then to_jsoned. There is no builder object, no json.key! calls and nothing to learn beyond Ruby. The first example is a hash literal, and the README's comment on it is the pitch in full: modern Ruby hash syntax pretty much looks like JSON syntax, so who needs a DSL to do this. A template does not have to be a single literal either. Any Ruby code that ends by returning a Hash works, which means conditionals, loops and helper calls are all available inside the template with no special syntax, including any helper that is available to views.
Two lines of installation, then name your file .jb
Installation is a Gemfile line:
gem 'jb'and then you bundle. Usage is: put a template file named *.jb in your Rails app's app/views/* directory and render it. A file such as app/views/messages/show.json.jb sits next to the .erb and .jbuilder templates you already have, so the routing and the format negotiation are unchanged; the extension is the whole registration. Partials work as you would expect, including collections, and you can pass objects in with or without the locals option, either as render 'sub_template', locals: {user: user} or as render 'sub_template', user: user.
Why it is faster, stated as a call count
The performance section is an argument about how many times a function runs rather than about microseconds, and it is more convincing because you can check it. Jbuilder's render partial with the :collection option internally calls its array! method, in which _render_partial is called for each element, and then falls back to the view context's render method. So for a collection of 100 elements, Jbuilder performs the render 100 times, which means calling find_template, described in the README as one of the heaviest parts of Action View, 100 times. Jb instead calls ActionView::PartialRenderer's render, which is implemented to find the template only once beforehand and then pass each element to it. One lookup instead of a hundred. The README also notes a small typo, writing OTOH where it means on the other hand, which is a reminder that this explanation was written by hand and is worth verifying against the linked source lines.
The collection bug it was built to fix
One of the three advertised features is that render_partial with the :collection option actually renders the collection, unlike Jbuilder. Given the previous section, that follows from the same mechanism: a library whose partial rendering falls back through the view context per element does not get the optimised collection path. The third feature is that there are no method_missing calls, which matters for both speed and for what static analysis and your editor can see; a builder DSL that responds to any name gives you no typo detection. The first feature, no original builder syntax to learn, is the one that decides adoption for a team, and it is a genuine trade rather than an improvement: jb has no DSL because it does not constrain how you build the structure.
An empty collection renders nil, not an empty array
The note in the partials section is the sharpest edge in the documentation: do not use render @post.comments, because if the collection is empty, render returns nil instead of an empty array. That means an API endpoint returns null where your client expects a list, and no exception is raised. The fix is the idiomatic Rails one shown next to it, rendering a partial for the collection explicitly with render partial: 'posts/post', collection: @posts, as: :post. For index actions the README suggests handling top level arrays directly in the template, since Ruby is good at collection manipulation and there is no special DSL method for extracting attributes from an array: you write @people.map {|p| {id: p.id, name: p.name}} and get an array of objects.
Nulls, compact and caching are plain Ruby
Three behaviours that a JSON layer usually takes over are left to you here, which is coherent with the design. Including nil as a hash value works and becomes null in the output. If you do not want nulls, Hash#compact and Hash#compact! do it, so {foo: nil, bar: 'bar'}.compact renders as a hash with only the bar key. And caching a fragment is a direct call to Rails.cache.fetch with your own key and expiry, shown with a version segment in the key. None of these are features of jb; they are features of Ruby and Rails that jb does not hide from you. The trade follows the rest of the design: more flexibility, and no guardrails when a template starts growing logic.
The scaffold generator writes .jb templates too
Requiring the gem changes generator output, which is the kind of thing that surprises a team halfway through a project. Jb extends the default Rails scaffold generator and adds .jb templates, and the README documents the off switch:
Rails.application.config.generators.jb falseThat is the entire configuration surface for the generator. Set it in an initialiser if you add the gem to an existing application and do not want new scaffolds emitting files your current conventions do not use, and note that existing .jbuilder or .erb templates keep working, since nothing here removes them.
Against Jbuilder and against a controller that renders json directly
The immediate comparison is Jbuilder, and the difference is the DSL. Jbuilder uses a builder DSL, while jb uses a Ruby expression. If your team likes the explicit builder style, or has templates full of it, jb is a migration rather than a swap. The other alternative is skipping view templates entirely and rendering JSON from the controller or serializer objects, which is the right answer when responses are consumed only by machines, since a view layer for JSON then buys you nothing. Jb's position is the middle case: humans still read these templates during debugging, there is a view to break into when something looks wrong, and the content stays Ruby instead of becoming a bespoke language.
Editorial conclusion
Jb fits a Rails codebase that finds Jbuilder's DSL heavier than the problem, especially where responses are assembled from collections, since the library does the same work with plain Ruby and a smaller API surface. Skip it if your team has invested in Jbuilder templates, or if you want a DSL that constrains structure, since jb deliberately has no original builder syntax and leaves composition to Ruby. Before adopting, read the collection rendering note, because `render @post.comments` can return nil for an empty collection rather than an empty array and that difference will show up as a null response rather than an error, and remember that the scaffold generator adds.jb templates unless you disable it with Rails.application.config.generators.jb false. The last push was on 2026-09-22, the project has no GitHub releases, and the licence is MIT.
Frequently asked questions
How do I install and use Jb in a Rails app?
Add gem 'jb' to the Gemfile and bundle. Then put a template file named *.jb under app/views/* and render it. Templates can be plain Ruby that returns a Hash or Array, and partials and collections work as they do in Action View.
Why is Jb faster than Jbuilder for collections?
Jbuilder's partial with :collection option calls its array! method and _render_partial per element, falling back to the view context's render, so a 100 element collection performs find_template 100 times. Jb calls ActionView::PartialRenderer's render, which finds the template once and then passes each element to it.
How do I stop Jb from changing my Rails scaffold generator?
Jb extends the default Rails scaffold generator with .jb templates. If you do not want that, configure Rails.application.config.generators.jb false in your application configuration.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/amatsuda-jb)