Getting started
Clone the Hotwire starter, install 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 dashboard. Budget 15 minutes if you already have Ruby and Docker installed; 30 if you don't. No Node.js, no npm install — Importmap serves JavaScript directly.
Prerequisites
| Tool | Version | Why |
|---|---|---|
| Ruby | matches .ruby-version (currently 3.3+) | App runtime. Install with rbenv, asdf, or mise. |
| Bundler | any recent | gem install bundler after Ruby is installed. |
| SQLite | 3.8.0+ | Rails app data, Solid Cache, Solid Queue, and Solid Cable all run on SQLite. The sqlite3 CLI must be on PATH. |
| Docker | recent | Required by supabase start (local stack) and by the Kamal deploy. Optional if you point the kit at Supabase Cloud. |
| Supabase CLI | 2.x | brew install supabase/tap/supabase, or official install docs. Only needed for a fully local Supabase stack. |
| Git | any | For cloning. |
Node.js is not required. JavaScript is served via Importmap; Tailwind is built by tailwindcss-rails from a precompiled binary.
1. Get the code
The starter is published as a standalone repo, not a generator — copy it, don't render it:
git clone https://github.com/supabase-ruby/starter-kit-hotwire my-app
cd my-appCommit 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-serverbin/setup is idempotent — re-run it any time. It runs bundle install, runs bin/rails db:prepare (which 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 in CI or while you're still filling in .env), or --reset to drop and recreate the SQLite files.
3. Set environment variables
Copy the template:
cp .env.example .envRails 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 three 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 in DockerThe CLI prints something like:
API URL: http://127.0.0.1:54321
anon key: eyJhbGciOi...
service_role key: eyJhbGciOi...Copy each into .env:
| CLI key | .env variable |
|---|---|
API URL | SUPABASE_URL |
anon key | SUPABASE_ANON_KEY |
service_role key | SUPABASE_SERVICE_ROLE_KEY |
The supabase/ directory is checked in — supabase start automatically applies the migrations under supabase/migrations/, including the public.notes table and its RLS policies.
B. Supabase Cloud
If you already have a project at supabase.com:
.env variable | Dashboard location |
|---|---|
SUPABASE_URL | Project Settings → API → Project URL |
SUPABASE_ANON_KEY | Project Settings → API → anon / public key |
SUPABASE_SERVICE_ROLE_KEY | Project Settings → API → service_role secret key |
For the Notes view to render any rows, you'll need to apply the supabase/migrations/ files to the Cloud project — either link the project (supabase link --project-ref <ref>) and run supabase db push, or paste the SQL into the dashboard's SQL editor.
The service_role key is server-only. It's used by the gem for admin-side calls (account deletion, admin user lookups). Never expose it to browsers.
4. Boot the dev server
bin/devbin/dev runs Procfile.dev, which starts bin/rails server on port 3000 and bin/rails tailwindcss:watch on a second process. Tailwind's watcher rebuilds app/assets/builds/application.css on every app/assets/tailwind/application.css change.
Then open http://127.0.0.1:3000.
5. Sign up your first user
The public landing page at /welcome has Log in and Register CTAs. Click Register and fill in an email + a password of 12 or more characters.
What happens behind the scenes:
- The form POSTs to
RegistrationsController#create(subclassed fromSupabase::Rails::RegistrationsController). - The gem calls Supabase Auth's sign-up endpoint with the anon key.
- Supabase emails a confirmation link. In development, the kit ships
letter_opener_web— open http://127.0.0.1:3000/letter_opener to read it without a real inbox. - Click the confirmation link in the email. Supabase confirms the account, sets the session, and redirects back to the kit.
- The gem's middleware unwraps the redirect, sets the encrypted
sb-sessioncookie, and you land on/authenticated.
If you don't see the dashboard chrome (sidebar + user menu), the cookie wasn't set — see Troubleshooting → Cookie isn't being set.
6. Visit the notes page
open http://127.0.0.1:3000/notesThe view at /notes lists rows from public.notes scoped to the signed-in user. The list will be empty on a fresh project — insert a row through the Supabase Studio at http://127.0.0.1:54323 (Table Editor → notes → "Insert row", with user_id = <your user UUID>) and the row appears on refresh. The full pattern is covered in Architecture → Per-request Supabase client.
7. Run the tests
bin/rails test # Minitest controllers + models
bin/rails test:system # Capybara + headless Chrome system testsTo run the end-to-end suite against your local Supabase stack:
bin/e2e # boots/reuses `supabase start`, runs test/e2e/bin/e2e is idempotent — if supabase start is already running it reuses it. First boot pulls Docker images and can take a few minutes. The full quality gate (bin/ci) chains everything together — see Deployment → CI.
Next
- Project structure — what each directory is for.
- Customization — adding Turbo Frames, Stimulus, and Supabase Realtime patterns.
Hotwire starter
Rails 8.1 server-rendered starter kit with Hotwire (Turbo + Stimulus), ViewComponent, Tailwind v4, and Supabase Auth via supabase-rails in :web mode with encrypted cookie sessions.
Project structure
A directory-by-directory walkthrough of the Hotwire starter — app/, config/, supabase/, db/, and test/ — at the level of detail a new contributor needs.