Why Next.js + Supabase is ideal for indie hackers
Indie hackers thrive on speed, focus, and leverage. Next.js + Supabase gives solo builders and small teams a modern full stack that is fast to prototype and reliable in production. Next.js handles the UI and server logic with React Server Components, Route Handlers, and file based routing. Supabase brings a hosted Postgres database with row level security, built in auth, storage, and realtime.
With this stack, you can ship a paid, secure SaaS with minimal infrastructure work. You get a powerful SQL database, type safe APIs, and edge ready rendering out of the box. If you want a head start on SaaS essentials like auth flows, billing pages, and a polished UI system, a starter like EliteSaas can accelerate your launch while keeping your stack clean and composable.
Getting started guide
1) Create a Next.js app
Use the App Router and TypeScript. Add Tailwind if you prefer a utility first UI.
- Run
npx create-next-app@latest, choose TypeScript and App Router - Add dependencies:
npm i @supabase/supabase-js @supabase/ssr zod - Optional UI:
npm i tailwindcss, then follow Tailwind setup
2) Provision Supabase
- Create a project in Supabase, note the project URL and anon key
- Install the CLI locally:
npm i -g supabase - Initialize locally:
supabase init, thensupabase startto run a local Postgres and Studio
3) Wire environment variables
Create .env.local in your Next.js app:
NEXT_PUBLIC_SUPABASE_URL=<project-url>NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>SUPABASE_SERVICE_ROLE_KEY=<service-role>for server only tasks
Never expose the service role key to the browser. Keep it in server code only.
4) Configure the Supabase client
Use the SSR helpers so cookies work across Server Components and Route Handlers.
- Server side: set up a helper using
createServerClientfrom@supabase/ssr, passcookies()from Next.js - Client side: use
createBrowserClientfor components that need realtime or client auth calls
Pattern: fetch data in Server Components whenever possible, keep client components small and interactive.
5) Enable authentication
- In Supabase Auth, enable email magic link and social providers like GitHub
- Create a
profilestable linked toauth.userswithuser_id uuid primary key - Turn RLS ON, add a policy like: users can select and update their own profile where
user_id = auth.uid()
Use Supabase Auth UI components or build custom forms. For indie hackers, email login plus GitHub is often enough to reduce friction.
6) Model your MVP data
Start with tables that map directly to user value, not internal admin concerns. Example for a simple subscription SaaS:
projectswithid,owner_id,name,created_atmembershipswithproject_id,user_id,roleeventsfor analytics or audit logs tied toproject_id
Add RLS policies that default deny and grant per user or team membership. Use Supabase migrations, commit SQL files to version control, and seed minimal test data for local development.
7) Build UI with the App Router
- Put public pages under
/app/(public)/, private under/app/(dashboard)/ - Use
layout.tsxto provide session context and nav - Create
route.tshandlers under/apifor server only operations - Use Server Actions for mutations that fit inside form submissions
This structure keeps navigation snappy and your data access secure through server boundaries.
Architecture recommendations
Design for secure-by-default data access
- Turn on RLS for every table from day one
- Write policies around
auth.uid()and membership joins, test with the anon key - Prefer the anon key with RLS for most reads and writes, reserve the service role key for administrative jobs
The combination of RLS and Supabase's typed client gives you a strong security posture without a complex backend.
Feature modules over monolith components
- Group by feature domain:
/app/(dashboard)/projects/,/lib/projects/,/db/migrations/ - Co-locate small server utilities per feature in
/lib, keep shared policies in/db - Use
revalidateTagorrevalidatePathto keep pages fresh when data changes
Runtime choices that match workload
- Edge runtime for latency sensitive reads and simple writes that use the anon key
- Node runtime for tasks that need the service role key, third party SDKs, or large dependencies
- Cache cautiously using Next.js headers and incremental revalidation, avoid caching personalized data
Background jobs and webhooks
- Use Supabase Functions or Vercel Cron for scheduled tasks like daily summaries
- For webhooks, create
/api/webhooks/*route handlers, validate HMAC signatures, queue work in the database - Leverage Postgres triggers or
pgmqstyle job tables if you want to stay in database
Storage and files
- Use Supabase Storage for user files, enforce RLS policies with signed URLs
- Keep metadata in Postgres so you can query and join with app data
- Generate thumbnails or derived assets via Functions to avoid heavy work in request cycles
Type safety and validation
- Generate TypeScript types from your database using the Supabase CLI
- Validate inputs at the edge using
zodschemas, map to SQL safely - Return typed responses from route handlers for predictable client code
Development workflow
Local development with parity
- Run
supabase startfor local DB and Auth,npm run devfor Next.js - Create
db/migrationsfolder, add SQL files, runsupabase db pushin CI - Maintain
db/seed.sqlwith realistic small data sets, reset withsupabase db reset
Branching and preview environments
- Use preview deployments for every Git branch, connect each to a Supabase branch or a disposable project when possible
- Gate risky changes behind a
feature_flagstable, roll out by user or organization - Track schema changes in PRs, require a green migration plan before merge
Testing strategy that fits indie-hackers
- Unit test pure utilities with Vitest
- API tests that hit local Postgres using a test database and seed data
- Playwright for E2E on happy paths like sign up, create project, invite member
- Smoke tests run on every preview deployment
Code quality without slowing down
- ESLint and Prettier in pre-commit hooks, TypeScript strict mode
- Small pull requests, daily merges, ship behind flags
- Use a UI kit with accessible components to avoid reinventing primitives
If you want a production ready baseline with authentication flows, settings pages, and subscription scaffolding, EliteSaas provides patterns and components that plug into a nextjs-supabase app without locking you in.
Deployment strategy
Recommended hosting
- Deploy Next.js on Vercel, connect Supabase as your managed Postgres and Auth
- Store
NEXT_PUBLIC_SUPABASE_URLandNEXT_PUBLIC_SUPABASE_ANON_KEYin Vercel environment variables - Keep
SUPABASE_SERVICE_ROLE_KEYin server only envs, never expose it to the client
Secrets and configuration
- Use separate projects for dev, staging, and prod
- Set allowed redirect URLs in Supabase Auth for each environment
- Rotate keys on a schedule, audit RLS policies quarterly
Zero downtime releases
- Backward compatible migrations first, code deploy second
- Avoid destructive changes in a single release, deprecate columns gradually
- Use Vercel preview builds to validate migrations against staging data
Performance and observability
- Use Postgres indexes for frequent filters and joins, monitor slow queries
- Instrument route handlers with logging, capture errors in Sentry
- Enable Postgres extensions cautiously, prefer native types like JSONB where appropriate
Payments and compliance basics
- Integrate Stripe with webhooks to
/api/webhooks/stripe, verify signatures - Store minimal customer data, keep PII encrypted at rest
- Respect user consent for analytics, provide simple account deletion
For deeper role based access, multi tenant dashboards, and subscription management, see Next.js + Supabase for Startup Founders | EliteSaas and agency scaling tips in Next.js + Supabase for Agencies | EliteSaas.
Conclusion
Next.js with Supabase gives indie-hackers a pragmatic path from idea to revenue. You get a battle tested React framework, a hosted Postgres with RLS, and a cohesive developer experience that minimizes glue code. Start with a thin slice of user value, secure it with policies, ship behind flags, and iterate fast. If you want a polished foundation with sensible defaults for auth, billing, and UI, EliteSaas helps you deliver a professional product without sacrificing control.
FAQ
Can I launch a paid MVP on free tiers?
Yes, you can get very far on free or low cost tiers. Next.js on Vercel free, Supabase free for small databases and modest auth traffic, Stripe with usage based fees. Keep background jobs lightweight, use scheduled Functions sparingly, and watch your database sizes. Upgrade when you reach consistent usage.
Should I use an ORM with Supabase or write SQL?
Either approach works. For many indie founders, plain SQL migrations plus the typed Supabase client is enough. If you want schema first type safety and composable queries, Drizzle is a good fit. Keep the number of abstractions low, make sure RLS is enforced regardless of ORM, and test queries under the anon role.
How do I keep the service role key secure in Next.js?
Do not load it in the browser. Use it only in server runtimes like Route Handlers, Server Actions, or background Functions. Store it as an environment variable in your host, restrict access to maintainers, and prefer anon key with RLS for most operations.
What is a simple way to handle webhooks and retries?
Create a dedicated /api/webhooks/* handler that validates the signature, writes the payload to a durable webhook_events table, and acknowledges quickly. Process the event asynchronously from the database, store idempotency keys, and log outcomes. This keeps your system robust against transient failures and double deliveries.
If you are a solo founder looking to move fast with nextjs-supabase patterns, also check Next.js + Supabase for Freelancers | EliteSaas for hands-on tips tailored to client work and side projects.