Self-hosted service
rootstrap/rails_api_base avatar
rootstrap/rails_api_base

rails_api_base is a Rails 8 API skeleton with the boring decisions already made

API boilerplate project for Ruby on Rails 8

633 stars137 forksRubyMIT

At a glance

What is it?
Rootstrap's rails_api_base is a MIT licensed boilerplate for JSON REST APIs on Rails 8.1 and Ruby 4.0, shipping Devise token authentication, Pundit authorisation, Flipper feature flags, an ActiveAdmin console, RSpec with OpenAPI generation, and a Docker path. Its real value is in the tooling decisions and the bin/ scripts that behave the same inside or outside Docker.
Who is it for?
rails_api_base is a sensible starting point for a team that has already decided it wants Rails, PostgreSQL, RSpec, an admin console and a Docker-based development flow, because the authentication, authorisation, pagination, feature flagging, background jobs and linting choices are already wired together and documented.
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 7 days 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 starting point covers auth, profiles, an admin panel and feature flags

Rails API Base is described as a boilerplate project for JSON RESTful APIs that follows community best practices in terms of standards, security and maintainability, integrating a variety of testing and code quality tools. It is based on Rails 8.1 and Ruby 4.0, and it contains a plug and play administration console thanks to ActiveAdmin.

What you get on the first day is concrete. The schema carries a users table and an admin users table. The endpoints cover sign up with user credentials, sign in with user credentials, sign out, reset password, and getting and updating the user profile. There is an administration panel, feature flag support with a UI for management, RSpec tests, an RSpec API Doc Generator, API documentation following OpenAPI, and Docker support.

That endpoint list is the part most teams would otherwise spend a day on. Authentication here is Devise for the basic side and Devise Token Auth for API authentication, which is what makes a JSON API usable from a client that cannot hold a session cookie. Authorisation is Pundit, and the endpoint set includes a reset password flow and profile endpoints rather than leaving you to decide what a user is allowed to do.

One note on scope: the repository has no GitHub releases, so there is no tagged version to pin. The last push was on 2026-10-16, and the template is meant to be forked and renamed rather than consumed as a dependency.

bootstrap.sh names the project and sets up both run modes

The getting started sequence is deliberately short, and the project naming is done by a script rather than by hand. After cloning, installing PostgreSQL and installing Node with the version pinned in the .nvmrc file, you install yarn, and the documented way to get the right yarn binaries is corepack enable, since corepack ships with recent Node versions.

Then the bootstrap script runs with your project name:

bash
    - `bin/bundle install`
    - `bin/rails console`
    - `bin/web ls`
    - `bin/rspec .`
    - `bin/dev`

Those are the dev scripts the template provides, and they are worth reading because of the promise attached to them: they are designed to run the same when running with Docker or not. The documentation spells out what that means, with bin/rails console running the console in the Docker container when running with Docker and locally when not.

That single property is what makes the template pleasant to use. A team member can work locally on a laptop without Docker and a colleague can run the same commands inside the compose network, and the difference is invisible in the command line.

The rest of the sequence is the usual loop: yarn install and yarn build --watch to bundle the JavaScript assets for the administration site using esbuild, then bundle exec rspec for the tests, with HEADLESS=true bundle exec rspec as the headless mode, then bin/dev to run the Rails and JS build processes together in a single terminal tab.

The Docker path leaves Postgres on 5432 unless you edit one key

The Docker instructions require docker and docker-compose, and the bootstrap script takes a different flag for that mode, the -d or --for-docker flag, with the details available from the bootstrap script's own help output.

The compose file itself is where the interesting decision sits. The web service builds from Dockerfile.dev, publishes port 3000 and waits for the database, and the db service runs postgres:16 with the authentication method set to trust. Both services have health checks, the web one running curl against localhost:3000 on a one minute and thirty second interval, and the database one running pg_isready every thirty seconds.

That last detail is the one to read twice. The db service also publishes its port:

yaml
    ports:
      - 5432:5432

and the documentation says that if you want to deny access to the database from outside of the docker-compose network, you remove the ports key in the docker-compose.yml from the db service. That is presented as optional, and on a laptop it is harmless. On a shared machine, or on a host where something else is listening on 5432, it is the difference between a local Postgres and a Postgres that anyone on the network can connect to, since the authentication method is trust.

The Docker path also has its own compose file for tests, docker-compose.test.yml, and its own test command, bin/rspec ., so the same specs run in both modes.

The gem list is where the template's real opinions live

Around forty gems are listed, and picking them apart tells you what a team that ships API products considers non-negotiable. Development is Ruby on Rails with Puma as the web server, Dotenv for environment variables and Rack CORS for CORS, configured through config/initializers/rack_cors.rb.

Testing is heavy on purpose: RSpec with Factory Bot and Faker for data, Shoulda Matchers for other matchers, Simplecov for coverage, Webmock for stubbing HTTP requests, Knapsack to split tests evenly based on execution time, and Parallel Tests to run them across multiple cores. Prosopite is there to detect N+1 queries, which is the kind of check that catches a performance bug before it reaches production rather than after.

Code quality is covered by three tools with different jobs: Rubocop for Ruby linting, Reek for code smell detection, and Rails Best Practices for Rails-specific linting, plus Brakeman for security static analysis. Strong Migrations catches unsafe migrations while you are still in development, and YAAF handles form objects.

The operational pieces are Flipper for feature flags, GoodJob for background processing, Pagy for pagination, New Relic for monitoring and debugging, Letter Opener for previewing emails in the browser, Rswag and rspec-openapi for serving and generating the API documentation, and Jbuilder for JSON views.

The trade-off is explicit: you inherit a large dependency surface and the opinions that come with it, and you will be asked to justify those choices in your own security review.

The production image builds assets with a dummy secret key

The Dockerfile is a multi-stage build with pinned base versions, RUBY_VERSION=4.0.5 and NODE_VERSION=22.7.0, and it takes the Node binaries from the official node image rather than installing Node inside the Ruby image.

The production environment is set through a block of environment variables, and two of them shape the image contents:

dockerfile
ENV BUNDLE_WITHOUT=development:test
ENV BUNDLE_DEPLOYMENT=1
ENV RAILS_ENV=production
ENV NODE_ENV=production

BUNDLE_WITHOUT excludes the development and test groups, so the linting, coverage and test gems listed above never reach the runtime image, and BUNDLE_DEPLOYMENT makes bundler fail rather than update a lock file during install.

Dependency installation runs corepack enable, then gem install bundler, bundle install -j 4 and yarn install --immutable, followed by a bootsnap precompile for faster boot times. The immutable flag on yarn matters: the yarn.lock file is copied into the image and the install is expected to match it exactly.

Asset precompilation runs with a placeholder secret:

dockerfile
RUN SECRET_KEY_BASE=DUMMY ./bin/rails assets:precompile

That avoids requiring the real RAILS_MASTER_KEY at build time, which is the correct approach for images built in CI. The runtime stage installs curl, libpq-dev, libvips and libjema, and the repository also carries a Procfile, a Procfile.dev and heroku.yml, so the same code has a documented path to Heroku as well as to a container platform.

Feature flags, admin and API docs each need their own credentials

Three of the template's headline features need configuration before they work, and the .env.sample file shows the shape of it. The email side is enabled through SendGrid using Rails' Action Mailer:

bash
SENDGRID_API_KEY=your_api_key

The served API documentation needs a username and password, SWAGGER_USERNAME and SWAGGER_PASSWORD, which is a sensible default for a documentation endpoint that describes your whole API. Monitoring uses NEW_RELIC_API_KEY and NEW_RELIC_APP_NAME, and the sample file even carries a development default for the app name.

The remaining variables point at the pieces you add later. AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_REGION and S3_BUCKET_NAME are there for object storage, PASSWORD_RESET_URL=http://127.0.0.1:3000 is the link your reset password emails will use, and SERVER_HOST covers the host the app believes it is running on. DOCKER_ENABLED=false and CHAOTIC_ORDER=true are switches the template itself reads, with the second name suggesting a deliberate fault injection mode for testing how the API fails.

The optional configuration list is short and specific: the frontend URL goes in config/initializers/rack_cors.rb, the mail sender in config/initializers/devise.rb, and the timezone in application.rb. Documentation for CI parallel execution and for fullstack development lives in the docs directory, alongside the Docker documentation.

The licence is MIT, and the tree carries the housekeeping a production Rails service needs: .devcontainer, sonar-project.properties, an infra directory, .hadolint.yml for linting the Dockerfiles, a .reek.yml for the Reek configuration, and separate Rubocop configuration and todo files.

Editorial conclusion

rails_api_base is a sensible starting point for a team that has already decided it wants Rails, PostgreSQL, RSpec, an admin console and a Docker-based development flow, because the authentication, authorisation, pagination, feature flagging, background jobs and linting choices are already wired together and documented. It is the wrong tool if you dislike Devise, if your Rails version is not 8.1, if you need a non-JSON API, or if you would rather not maintain a large dependency list, since the gem set runs to around forty entries. Verify first that the bootstrap script completes on your machine, that the database is not reachable from outside your machine in the Docker path, and that the Ruby and Node versions in .ruby-version and .nvmrc match what your CI runs.

Frequently asked questions

How do I start a new project from rails_api_base?

Clone the repository, install PostgreSQL, Node with the version in .nvmrc and yarn via corepack enable, then run ./bin/bootstrap.sh --name=my_awesome_project. Follow it with yarn install and yarn build --watch, bundle exec rspec, and bin/dev to run the app.

Which versions of Ruby and Rails does the template target?

It is based on Rails 8.1 and Ruby 4.0, with the Dockerfile pinning RUBY_VERSION=4.0.5 and NODE_VERSION=22.7.0, and the repository carries .ruby-version and .nvmrc for the Ruby and Node versions.

Does the Docker setup expose the database to my network?

By default the compose file publishes the db service on port 5432 and sets the postgres authentication method to trust. To deny access from outside the compose network, remove the ports key from the db service in docker-compose.yml.

Which quality and test tools come with the template?

Rubocop, Reek and Rails Best Practices for linting, Brakeman for security static analysis, Strong Migrations for unsafe migrations, Prosopite for N+1 queries, RSpec with Factory Bot, Faker, Shoulda Matchers, Simplecov, Webmock, Knapsack and Parallel Tests.

How are the API docs produced and served?

The RSpec API Doc Generator, rspec-openapi, produces the documentation from request specs, and Rswag serves the generated docs, which follow OpenAPI. The served documentation is protected by the SWAGGER_USERNAME and SWAGGER_PASSWORD variables in .env.sample.

Official sources

  1. Issues
  2. License: MIT
  3. Project website
  4. README
  5. rootstrap/rails_api_base on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rootstrap-rails-api-base.svg)](https://hysenlabs.com/projects/rootstrap-rails-api-base)

Was this useful?