Skip to content

ADR-0002: Supabase for auth/DB/storage, NestJS as the API in front

Status: Accepted
Date: 2026-05-02
Owner: @satya

Treeper needs:

  • Auth (email + Google + Apple at minimum) with minimal in-house code.
  • Postgres.
  • Object storage for trip cover images and inline photos.
  • Realtime channels later (community feed, trip group chat).
  • A backend tier for non-trivial business logic: AI worker orchestration, scraper coordination, marketplace verification, search.

Two natural ends of the spectrum:

  1. Pure Supabase: clients call PostgREST/Edge Functions directly; RLS enforces auth.
  2. Pure NestJS: roll our own Postgres + custom auth, ignore Supabase.

Both are wrong for us.

Supabase owns auth, primary Postgres, and Storage. NestJS sits in front of it as the canonical REST API. Mobile clients only talk to NestJS, except for direct uploads to Supabase Storage with short-lived signed URLs issued by NestJS.

NestJS verifies Supabase-issued JWTs via passport-jwt against Supabase’s JWKS. RLS in Postgres is treated as a defence-in-depth layer, not the only authorisation gate.

OptionWhy not
Pure Supabase (PostgREST + EFns)Forces Edge Functions for non-CRUD logic; harder to test, harder to host elsewhere.
Pure NestJS + custom PostgresReinvents auth and storage, and we lose Supabase’s free OAuth providers.
Hasura / PostGraphQLMore tooling than this team needs at v0. Revisit if/when we need a federated graph.
FirebaseLock-in to Google’s auth + Firestore data model; we want Postgres.
  • Auth ships in a day, not a sprint.
  • Postgres = real schema, real migrations, real query power.
  • We can leave Supabase later by replacing only the auth and storage adapters; the API surface stays the same.
  • One source of truth for the mobile client: the NestJS API.
  • Two systems to operate (Supabase project + our own backend host).
  • JWT verification adds a small per-request hop; cache JWKS aggressively.
  • RLS rules duplicate some checks NestJS also enforces; we accept that as defence-in-depth.
  • ADR on schema migration tool (Prisma vs Drizzle vs raw SQL).
  • ADR on file upload flow (signed URLs vs proxy through NestJS).
  • Spec out auth UX in feature 0001’s scope: sign in, sign out, account delete.