Building a Lean JSON API with Rails API‑Only Mode: Setup, Middleware, and Trade‑offs
Learn how Rails API‑Only mode cuts the stack for JSON services, set up middleware, build a Product API, and understand the trade‑offs. A practical guide with code snippets and a checklist.
21 Mar 2026, 08:24 UTC

Problem: A Heavy Rails Stack for a Pure JSON Service
When you need a server that only talks JSON—think mobile back‑ends, single‑page applications, or micro‑services—running a full Rails application can feel like overkill. The default Rails stack loads view helpers, asset compilers, and session middleware that you never use, adding memory usage, startup time, and attack surface.
Thesis: Rails API‑Only Mode Is the Right Tool for a Lightweight JSON API
Since Rails 5, the framework offers an --api flag that strips the stack to the essentials needed for building a JSON‑only service. It removes view rendering, asset pipeline, and session helpers, but keeps routing, ActiveRecord, ActionController, and the request/response cycle. This blog walks through why you’d choose API mode, how to set it up, tweak middleware, and what you lose.
1. What API Mode Removes and Why It Matters
- View and Asset Middleware:
ActionDispatch::Static,ActionView,Sprocketsare omitted because an API never serves HTML or compiled assets. - Session and Flash: The default cookie‑based session store and flash helpers are removed. If per‑user state is needed, you must add a session middleware manually.
- Helpers and Layouts: All view helpers, layout rendering, and helper modules are skipped.
- Rack::MethodOverride: Removed by default; add back if you need legacy form‑based method overrides.
Benefits include faster boot time, lower memory footprint, and fewer security vectors because unneeded code paths aren’t loaded.
2. Setting Up an API‑Only Application
# Create a new Rails API project
rails new myapi --api
The generated config/application.rb contains a slimmed middleware stack. Verify the stack by inspecting the file:
module Myapi
class Application < Rails::Application
config.load_defaults 7.0
config.api_only = true
# Middleware that is still loaded
config.middleware.use ActionDispatch::ParamsParser
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
end
end
To add or remove middleware, edit config/application.rb or create an initializer in config/initializers. For example, to enable CORS for a React front‑end:
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'https://app.example.com'
resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options]
end
end
If you need session support, uncomment the session middleware line or add a custom store:
config.middleware.use ActionDispatch::Session::CookieStore, key: '_myapi_session'
3. Worked Example: A Simple Product API
- Generate a model and controller:
rails g model Product name:string price:decimal rails g controller Products index show - Define routes in
config/routes.rb:Rails.application.routes.draw do resources :products, only: [:index, :show] end - Implement controller actions (
app/controllers/products_controller.rb):class ProductsController < ApplicationController def index @products = Product.all render json: @products end def show @product = Product.find(params[:id]) render json: @product end end - Run migrations and start the server:
rails db:migrate rails s - Test the API with curl:
curl http://localhost:3000/products
Expected output is a JSON array of products. If you see an empty array, confirm the database has records or seed data. Use rails c to create sample products manually.
4. Trade‑offs and Limitations
- No View Helpers or Layouts: Any feature that relies on
ActionView(e.g.,link_to,form_with) must be re‑implemented or omitted. - Asset Pipeline Missing: Static files (CSS, JS) are not served by Rails. Use a CDN, S3, or a dedicated asset server.
- Testing Constraints: View‑centric test helpers are unavailable. Use
json_responsehelpers or parseresponse.bodymanually in controller specs. - Session and Flash Disabled: If you need per‑user state, add the session middleware manually or use JWTs.
- ActionCable Requires Explicit Middleware: To enable WebSockets, add
ActionCable.server.config.cableand theActionCable::Server::Middlewaremanually.
Rails 7 adds optional Turbo and Hotwire support to API mode, but you must configure them explicitly. If you plan to use Hotwire streams, include the Turbo::StreamsChannel and related middleware.
Actionable Checklist Before You Deploy
- Run
rails new myapi --apiand inspectconfig/application.rbfor the middleware stack. - Add CORS, sessions, or ActionCable middleware only if your service requires them.
- Seed the database or create a test record to confirm JSON responses.
- Use
curlor Postman to hit each endpoint and verify JSON payloads and status codes. - Run
rails testorrspecto ensure controller specs parse JSON correctly. - Benchmark with
wrkorabto confirm performance gains over a full Rails stack. - Deploy to a staging environment and monitor memory usage and response times.
By following these steps, you’ll have a lean Rails API that’s fast, secure, and easy to maintain.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.