Next.js 15 + Supabase • RLS‑first • TanStack Query

Ship a real multi‑tenant SaaS in days, not months

Supajump gives you Organizations → Teams → Users, dynamic RBAC with Row‑Level Security, RSC‑first data fetching, and a batteries‑included DX — all wired up in a Turborepo.

Read the README
Works great locally: supabase start + pnpm dev

Powered by your favorite stack

Next.js 15
Supabase
Postgres RLS
TanStack Query
Turborepo
Tailwind

Everything you actually need

Supajump packages the hard parts so you can focus on your product: auth, permissions, data fetching, and a maintainable file structure.

Tenant model

True Multi‑Tenancy

Organizations → Teams → Users with memberships and role assignments. Clean tenant isolation and sane defaults.

Security

Dynamic RBAC + RLS

Permission = resource + action + scope (all/own). Enforced via Postgres Row Level Security and helper RPCs.

Performance

RSC‑first Data

React Server Components with server‑side prefetch + client hydration using TanStack Query.

DX

Feature‑based Codebase

Organized by feature folders with colocated components, hooks, queries, and types.

CLI

CLI Scaffolder

npx/pnpm create to bootstrap a new project with env scaffolding and clear next steps.

UX

Polished UX

Skeleton loaders, react‑hook‑form + zod, and sensible defaults for a production‑ready feel.

Monorepo, organized

  • /apps/app – Next.js application
  • /packages/create-supajump-app – CLI scaffold
  • /packages/* – shared packages

Code conventions

  • No semicolons, double quotes
  • Strict import ordering (Prettier)
  • Path aliases: @/*, @features/*
  • Environment validation in env.mjs

From zero to tenant‑aware in three steps

Step 1

Create

Scaffold a new project with the CLI.

npx @supajump/create-app my-app
Step 2

Develop

Run Supabase + the app locally.

cd my-app && supabase start && pnpm dev
Step 3

Ship

Build with confidence. RBAC + RLS are already wired in.

pnpm build

Type‑safe DB

Database types auto‑generated to apps/app/src/lib/database.types.ts.

Feature folders

Colocate UI, hooks, queries, and types under /features/[name].

Query cache keys

Centralized keys in /apps/app/src/queries/keys.ts for proper invalidation.

Production patterns, pre‑wired

These are the real patterns the template ships with — not hand‑wavy pseudo‑code.

RSC prefetch + hydrate (TypeScript)
// RSC with server-side prefetch + hydration
import { HydrationBoundary, dehydrate } from "@tanstack/react-query"
import { getQueryClient } from "@/components/providers/get-query-client"
import { api } from "@/queries"
import { postsKeys } from "@/queries/keys"

export default async function Page({ params }) {
  const supabase = await createClient()
  const queryClient = getQueryClient()
  await queryClient.prefetchQuery({
    // eslint-disable-next-line @tanstack/query/exhaustive-deps
    queryKey: postsKeys.list(orgId, teamId),
    queryFn: () => api.posts.getAll(supabase, orgId, teamId),
  })
  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <PostsTable orgId={orgId} teamId={teamId} />
    </HydrationBoundary>
  )
}
RLS policy template (SQL)
-- RLS helper pattern (simplified)
CREATE POLICY "rls_<table>_select" ON <table>
FOR SELECT TO authenticated USING (
  supajump.has_permission('<table>', 'view', org_id, team_id, owner_id)
);

CREATE POLICY "rls_<table>_insert" ON <table>
FOR INSERT TO authenticated WITH CHECK (
  supajump.has_permission('<table>', 'create', org_id, team_id, owner_id)
);

CREATE POLICY "rls_<table>_update" ON <table>
FOR UPDATE TO authenticated WITH CHECK (
  supajump.has_permission('<table>', 'edit', org_id, team_id, owner_id)
);

CREATE POLICY "rls_<table>_delete" ON <table>
FOR DELETE TO authenticated WITH CHECK (
  supajump.has_permission('<table>', 'delete', org_id, team_id, owner_id)
);
TanStack hook (TypeScript)
// Client hook
export function usePosts(orgId, teamId) {
  const supabase = createClient()
  return useQuery({
    // eslint-disable-next-line @tanstack/query/exhaustive-deps
    queryKey: postsKeys.list(orgId, teamId),
    queryFn: () => api.posts.getAll(supabase, orgId, teamId),
  })
}
Essential commands (bash)
# Development
supabase start
pnpm dev

# Build / Lint
pnpm build
pnpm lint

# DB management
pnpm db:gen:types
supabase db push
supabase db reset

Feature skeletons, not spinners

Supajump ships with skeleton components that mirror layouts for instant perceived performance.

FAQ

Is Supajump framework‑opinionated?
Yes — Next.js 15, React Server Components, TanStack Query, Tailwind. The goal is speed to a solid baseline without bikeshedding.
How does authorization work?
Roles and permissions are stored in Postgres. A helper function checks resource, action, and scope (own/all) to enforce RLS across tables.
Can I extend the data model?
Yes. Follow the RLS policy template and use the feature folder pattern to add tables, queries, and UI with minimal friction.
Where do queries live?
All queries are centralized in /apps/app/src/queries and exposed via an api object for consistency and testability.
Local dev flow?
Run supabase start, then pnpm dev. After schema changes, run pnpm db:gen:types to refresh types.
View on GitHub