Rails API starter
Rails 8 API-only starter kit that authenticates clients with Supabase Auth via supabase-rails — JWT verification, rswag OpenAPI docs, Rack::Attack rate limiting, and a Kamal deploy config.
The Rails API starter is a thin, production-shaped Rails 8 backend for clients that already have a Supabase identity. Mobile apps, single-page apps, and other server-to-server callers sign in directly with Supabase, then call this API with Authorization: Bearer <jwt>. The starter never mints its own sessions, never holds a cookie, never serves HTML — it verifies the JWT on every request through supabase-rails middleware, populates Current.user from the verified claims, and returns JSON.
What is it
A :api-mode Rails 8 app pre-wired with the pieces every JSON API needs the day it ships:
- JWT auth —
supabase-railsmiddleware in front of/api/*verifies tokens against your project's JWKS. Invalid tokens never reach a controller. - Rate limiting —
Rack::Attackruns ahead of JWT verification with two throttles (per-IP and per-token) on/api/*. - CORS —
Rack::Corsdriven by aCORS_ORIGINSenv var; safe-by-default (no origins allowed in production until you set it). - OpenAPI —
rswagintegration specs are the source of truth forswagger/v1/swagger.yaml, served at/api-docsbyrswag-ui. - Tests — RSpec request specs and rswag integration specs that mint real signed JWTs against an in-memory JWKS.
- Deploy —
Dockerfileand a Kamalconfig/deploy.ymlfor a single-command production push.
Who it's for
You should pick this kit when:
- Your authenticated clients are not browsers asking the same Rails app to render HTML — they're a mobile app, an SPA, a CLI, or another backend.
- You want Supabase Auth to own the identity surface (sign-up, email confirmation, OAuth, password reset, MFA) and your Rails app to focus on domain logic.
- You'd rather verify a JWT on every request than carry a server-side session.
If your frontend is a Rails view layer, look at the Hotwire or Inertia + React starters instead — both run supabase-rails in :web mode with cookie sessions, which is the right shape for a server-rendered monolith.
What's included
| Layer | What ships in the box |
|---|---|
| Auth | supabase-rails middleware, Authentication concern, JsonUnauthorizedResponder for canonical 401 bodies |
| Endpoints | GET /api/v1/me (authenticated), GET /healthz (public liveness), GET /up (Rails default) |
| Throttling | Rack::Attack with api/ip (300/5min) and api/token (1000/min) limiters |
| CORS | Rack::Cors keyed off CORS_ORIGINS, off-by-default in production |
| Tests | RSpec request specs, rswag integration specs, Minitest infrastructure tests, SupabaseAuthHelper JWT minter |
| Docs | swagger/v1/swagger.yaml, /api-docs UI gated by SWAGGER_UI_ENABLED in production |
| Deploy | Dockerfile, Kamal config/deploy.yml, .kamal/secrets template, Hetzner-shaped defaults |
What's not included
The kit is deliberately small so you can grow it in whichever direction your product needs. It does not ship:
- A domain model. There's no
UserAR record, no business-logic models, no migrations beyond Solid Cable/Cache/Queue schemas.Current.useris a value object built from JWT claims — opt into a host-appuserstable later withbin/rails generate supabase:user_model. - Server-rendered views or cookie sessions.
config.api_only = true, noActionDispatch::Cookies, no CSRF tokens. If you need either, use the Hotwire or Inertia starters. - A background job pipeline. Solid Queue is configured but unused — the kit has no jobs.
- Per-target deploy guides.
Dockerfileand Kamal config are generic; turning them into a Fly/Render/Heroku flow is left to your platform. - Multi-tenancy primitives. No org/team scoping, no per-tenant Postgres schemas — bring your own.
- Observability. Logs go to STDOUT, nothing else. Wire up your APM (Sentry, Datadog, OpenTelemetry) when you need it.
Next
Getting started
Prerequisites, clone, install, env, and your first authenticated request.
Project structure
Walkthrough of app/, config/, db/, spec/, and swagger/ for a new contributor.
Architecture
How supabase-rails plugs into the middleware stack, request lifecycle, and the JWKS verification path.
Customization
Add a resource, gate a public route behind auth, change the database schema.
Deployment
Production-readiness checklist — secrets, TLS, rate-limit cache, health checks.
Troubleshooting
First-run failures and how to read them — 401 loops, missing env, CORS, JWKS.
Repository
- Source:
supabase-ruby/starter-kit-api - Underlying gem:
supabase-rails
Starter Kits
Production-ready Rails starter kits wired up with Supabase Auth via supabase-rails — pick the shape that matches your app (API-only, Hotwire monolith, or Inertia + React) and clone.
Getting started
Clone the Rails API starter, install dependencies, point it at a Supabase project, and make your first authenticated request.