A simple & fast solution for Rails JSON rendering.
In Gemfile
gem 'simple_json'In controller
class ApplicationController < ActionController::Base
include SimpleJson::SimpleJsonRenderable
...
endIn view, create your simple_json template file in app/views.
# {controller_name}/{action_name}.simple_json.rb
{
key1: @value1,
key2: helper(@value2),
key3: partial!("partial_path", param1: param1, param2: param2)
}And, partial as well.
->(param1:, param2:) {
{
key1: param1,
key2: param2,
}
}That's all!
Have fun!
This project is built on work of jb.
SimpleJson templates should be written in Ruby lambda format. The template code is converted into a method and then invoked to produce data (Hashes or Arrays) for JSON.
-> {
{
key: @value,
}
}When no parameters specified, -> { and } can be omitted.
{
key: @value,
}Use partial! method to call another template in template. Note that path is always required. Also, there is no difference between partials and templates, so that you cannot omit _ before template name.
(So, no omitting for template path is allowed.)
# app/views/posts/show.simple_json.rb
{
title: @post.title,
comments: @post.comments.map { |comment| partial!('comments/_comment', comment: comment) }
}# app/views/comments/_comment.simple_json.rb
->(comment:) {
{
body: comment.body
}
}Cache helpers of simple_json is similar to jbuilder.
cache! key, options do
data_to_cache
endCache helpers uses Rails.cache to cache, so array keys, expirations are available. Make sure perform_caching is enabled.
cache! [key1, key2], expires_in: 10.minutes do
data_to_cache
endcache_if! is also available
cache_if! boolean, key1, options do
data_to_cache
endYou can set key_prefix for caching like this
SimpleJson.cache_key_prefix = "MY_PREFIX"Load all templates on boot. (For production) Templates loaded will not load again, so it is not recommended in development environment.
# config/environments/production.rb
SimpleJson.enable_template_cacheThe default path for templates is app/views, you can change it by
SimpleJson.template_paths.append("app/simple_jsons")
# or
SimpleJson.template_paths=["app/views", "app/simple_jsons"]Note that these paths should not be eager loaded cause using .rb as suffix.
SimpleJson uses ActiveSupport::JSON as the default JSON serializer. If you want to change to a module that has #encode and #decode methods, such as the Oj gem, you can do so as follows.
# define Custom Json class
# ex. config/initializers/simple_json/json.rb
module SimpleJson
module Json
class Oj
def self.encode(json)
::Oj.dump(json, mode: :rails)
end
def self.decode(json_string)
::Oj.load(json_string, mode: :rails)
end
end
end
end
SimpleJson.json_module = SimpleJson::Json::OjSimpleJson extends the default Rails scaffold generator and adds some simple_json templates. If you don't need them, please configure like so.
Rails.application.config.generators.simple_json falseHere're the results of a benchmark (which you can find here in this repo) rendering a collection to JSON.
% ./bin/benchmark.sh
SimpleJson Benchmark
ruby: 4.0.1
rails: 8.1.1
json: 2.15.2
oj: 3.16.11
----------------------
* Rendering 10 partials via render_to_string
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [arm64-darwin24]
Warming up --------------------------------------
jb 23.000 i/100ms
jbuilder 30.000 i/100ms
simple_json(oj) 40.000 i/100ms
simple_json(AS::json)
46.000 i/100ms
Calculating -------------------------------------
jb 298.518 (±23.4%) i/s (3.35 ms/i) - 1.426k in 5.019370s
jbuilder 255.925 (± 4.3%) i/s (3.91 ms/i) - 1.290k in 5.052973s
simple_json(oj) 270.192 (± 3.7%) i/s (3.70 ms/i) - 1.360k in 5.039635s
simple_json(AS::json)
297.476 (±10.1%) i/s (3.36 ms/i) - 1.518k in 5.145803s
Comparison:
jb: 298.5 i/s
simple_json(AS::json): 297.5 i/s - same-ish: difference falls within error
simple_json(oj): 270.2 i/s - same-ish: difference falls within error
jbuilder: 255.9 i/s - same-ish: difference falls within error
* Rendering 100 partials via render_to_string
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [arm64-darwin24]
Warming up --------------------------------------
jb 19.000 i/100ms
jbuilder 14.000 i/100ms
simple_json(oj) 15.000 i/100ms
simple_json(AS::json)
26.000 i/100ms
Calculating -------------------------------------
jb 186.051 (±12.9%) i/s (5.37 ms/i) - 912.000 in 5.075117s
jbuilder 144.279 (± 2.1%) i/s (6.93 ms/i) - 728.000 in 5.048538s
simple_json(oj) 159.254 (± 1.9%) i/s (6.28 ms/i) - 810.000 in 5.088178s
simple_json(AS::json)
249.690 (± 6.0%) i/s (4.00 ms/i) - 1.248k in 5.017042s
Comparison:
simple_json(AS::json): 249.7 i/s
jb: 186.1 i/s - 1.34x slower
simple_json(oj): 159.3 i/s - 1.57x slower
jbuilder: 144.3 i/s - 1.73x slower
* Rendering 1000 partials via render_to_string
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [arm64-darwin24]
Warming up --------------------------------------
jb 4.000 i/100ms
jbuilder 2.000 i/100ms
simple_json(oj) 2.000 i/100ms
simple_json(AS::json)
10.000 i/100ms
Calculating -------------------------------------
jb 48.691 (± 2.1%) i/s (20.54 ms/i) - 244.000 in 5.013815s
jbuilder 27.930 (± 3.6%) i/s (35.80 ms/i) - 140.000 in 5.016897s
simple_json(oj) 29.083 (± 6.9%) i/s (34.38 ms/i) - 146.000 in 5.039076s
simple_json(AS::json)
99.792 (± 7.0%) i/s (10.02 ms/i) - 500.000 in 5.037716s
Comparison:
simple_json(AS::json): 99.8 i/s
jb: 48.7 i/s - 2.05x slower
simple_json(oj): 29.1 i/s - 3.43x slower
jbuilder: 27.9 i/s - 3.57x slower
When migrating from Jbuilder, you can include Migratable in controller for migrating mode.
include SimpleJson::SimpleJsonRenderable
include SimpleJson::Migratable
In migrating mode
- Comparision will be performed for simple_json and ActionView render(Jbuilder) result.
- simple_json partials not found will use Jbuilder partial as an alternative.
Note that render will be performed twice, so using it in production mode is not recommended.
Pull requests are welcome on GitHub at https://github.com/aktsk/simple_json.
The gem is available as open source under the terms of the MIT License.