supabase-rb-rb
Inertia + React starter

Getting started

Clone the Inertia + React starter, install Ruby + Node dependencies, point it at a Supabase project, and sign in for the first time.

This guide takes you from a clean machine to a signed-in React dashboard. Budget 15 minutes if you already have Ruby, Node, and Docker installed; 30 if you don't.

Prerequisites

ToolVersionWhy
Rubymatches .ruby-version (4.0.x)App runtime. Install with rbenv, asdf, or mise.
Bundlerany recentgem install bundler after Ruby is installed.
Node.js22.x (matches the NODE_VERSION arg in Dockerfile)Vite, the React build, and (optionally) the SSR runtime.
npmbundled with Node 22The kit uses npm, not pnpm or yarnpackage-lock.json is checked in.
SQLite3.8.0+Rails app data, Solid Cache, Solid Queue, Solid Cable. The sqlite3 CLI must be on PATH.
DockerrecentRequired by supabase start (local stack) and by the Kamal deploy. Optional if you point the kit at Supabase Cloud.
Supabase CLI2.xbrew install supabase/tap/supabase, or official install docs. Only needed for a fully local Supabase stack.
GitanyFor cloning.

1. Get the code

The starter is a standalone repo — clone it, don't render it from a generator:

git clone https://github.com/supabase-ruby/starter-kit-inertia-react my-app
cd my-app

Commit it into a fresh repo of your own, or keep the upstream remote if you want to pull future starter updates.

2. Run bin/setup

bin/setup --skip-server

bin/setup is idempotent — re-run it any time. It runs bundle install, npm install, bin/rails db:prepare (creates the four SQLite databases — primary, cache, queue, cable), and clears log/ and tmp/. Pass --skip-server to skip the auto-launch of bin/dev (useful while you fill in .env), or --reset to drop and recreate the SQLite files.

The Node install pulls in React 19, Vite 8, the Inertia adapter, Tailwind v4, and the shadcn/ui dependencies (Radix, Lucide, class-variance-authority, tailwind-merge).

3. Set environment variables

Copy the template:

cp .env.example .env

Rails does not auto-load .env — the file is read by your shell (via direnv, dotenv, or your process manager) before bin/dev runs. The supplied .env.example documents this at the top.

You need four Supabase values. Pick A or B depending on whether you want a fully local Supabase or a Cloud project.

A. Local Supabase via the CLI

From the project root:

supabase start    # boots Auth + Postgres + Studio + Mailpit in Docker

The CLI prints something like:

         API URL: http://127.0.0.1:54321
        Publishable: sb_publishable_...
        Secret: sb_secret_...

Run supabase status -o env to see every key (including the JWT secret) printed as shell-style env vars. Copy each into .env:

supabase status field.env variable
API URLSUPABASE_URL
PublishableSUPABASE_PUBLISHABLE_KEY
SecretSUPABASE_SECRET_KEY
derived: <SUPABASE_URL>/auth/v1/.well-known/jwks.jsonSUPABASE_JWKS_URL

SUPABASE_JWKS_URL is not printed by the CLI — derive it from SUPABASE_URL. Locally that's http://127.0.0.1:54321/auth/v1/.well-known/jwks.json.

B. Supabase Cloud

If you already have a project at supabase.com:

.env variableDashboard location
SUPABASE_URLProject Settings → API → Project URL
SUPABASE_PUBLISHABLE_KEYProject Settings → API Keys → Publishable (sb_publishable_...)
SUPABASE_SECRET_KEYProject Settings → API Keys → Secret (sb_secret_...)
SUPABASE_JWKS_URL<SUPABASE_URL>/auth/v1/.well-known/jwks.json

The secret key is server-only. Never expose it to browsers.

4. Boot the dev server

bin/dev

bin/dev runs Procfile.dev, which starts two processes:

  • bin/rails s -p 3000 — the Rails app.
  • npx vite — the Vite dev server on port 5173, with HMR.

The rails-vite-plugin middleware in dev proxies asset requests to Vite, so you only ever browse http://localhost:3000 — Vite is transparent. The first request also triggers Typelizer to regenerate app/javascript/routes/*.ts from config/routes.rb.

Then open http://localhost:3000.

5. Sign up your first user

The public landing page at / has Sign in and Sign up CTAs. Click Sign up and fill in an email + password.

What happens behind the scenes:

  1. The form (a React <Form> from @inertiajs/react) POSTs to RegistrationsController#create.
  2. The controller calls supabase_sign_up(email:, password:), which hits Supabase Auth's sign-up endpoint with the publishable key.
  3. Supabase emails a confirmation link.
    • Local: the mail lands in Mailpit / Inbucket at http://127.0.0.1:54324.
    • Cloud: check the email Supabase sent to the address you signed up with.
  4. Click the link. Supabase confirms the account, redirects through the kit's OAuth callback, and supabase-rails mints the encrypted sb-session cookie.
  5. You land on /dashboard authenticated — the sidebar shows your email in the bottom-left menu.

If the React shell renders without auth (no sidebar), the cookie wasn't set — see Troubleshooting → Cookie isn't being set.

6. Toggle the appearance

The kit ships a working theme switcher at /settings/appearance (light / dark / system). It writes the choice to localStorage and toggles the dark class on <html> via the useAppearance hook — there's no round-trip to Rails for the toggle itself.

7. Run the tests

bin/rspec                         # request specs under spec/requests/

The request specs use SupabaseAuthHelpers (in spec/support/) to stub resume_session on ApplicationController, so you can sign_in_as(email:, name:) without an HTTP round-trip to Supabase. Fast and hermetic.

The frontend has its own quality gates that are part of bin/ci:

npm run lint                      # eslint over app/javascript
npm run format                    # prettier check
npm run check                     # tsc on app + node configs

bin/ci chains all of the above plus Rubocop, Brakeman, bundler-audit, npm audit, and the RSpec suite — see Deployment → CI.

Next

  • Project structure — what each directory is for, both Rails and React sides.
  • Architecture — Inertia request lifecycle, the Vite + React frontend layer, and how supabase-rails plugs in.
  • Customization — adding an Inertia page, a shadcn component, and a Supabase Realtime channel.

On this page