Supabase Setup
Initialize migrations, apply them, and configure RLS for tenant isolation with @stndrds/adapter-supabase.
@stndrds/adapter-supabase provides the database adapter and typed repository layer. This guide covers initializing migrations, applying them, and configuring RLS for tenant isolation.
Initialize
standards requires several core tables: actors, actor_roles, record_reference_edges, records, object_definitions, and more. These are all defined in the baseline migration shipped with standards-platform.
@stndrds/adapter-supabase does not expose its own CLI or migration runner. Migrations live in your project's supabase/migrations/ directory (following the Supabase convention) and are applied with the Supabase CLI.
Copy the baseline migration from standards-platform to get started:
# In your project root (requires supabase CLI)
cp path/to/standards-platform/supabase/migrations/20260516000000_stndrds_initial_schema.sql \
supabase/migrations/The @stndrds/adapter-supabase package exports types, repository helpers, and filter utilities — not a migration runner. All schema setup is done via the Supabase CLI.
Migration commands
Use the Supabase CLI directly. The scripts/setup.sh in standards-platform shows the full initialization sequence:
# Start local Supabase (Docker)
pnpm exec supabase start
# Apply all pending migrations to local DB
pnpm exec supabase db push
# Reset and re-apply from scratch (dev only)
pnpm exec supabase db resetFor production, run supabase db push against your hosted project:
supabase db push --db-url postgresql://postgres:<password>@<host>:5432/postgresThere is no @stndrds/adapter-supabase migrate CLI command. The adapter is a pure runtime library.
RLS policies
standards relies on Postgres RLS for tenant isolation. Every core table has a tenant_isolation policy using current_setting('app.tenant_id', true). The adapter sets this session variable before each query.
The production pattern from standards-platform's migrations:
alter table public.records enable row level security;
create policy records_tenant_isolation
on public.records
using (tenant_id = (current_setting('app.tenant_id', true))::uuid)
with check (tenant_id = (current_setting('app.tenant_id', true))::uuid);Apply the same pattern to any custom tables you add. The with check clause enforces the tenant on writes; using enforces it on reads.
For the full set of production policies, refer to standards-platform/supabase/migrations/20260516000000_stndrds_initial_schema.sql.
Always run migrations with the service-role key. RLS does not apply to migration scripts — the service role bypasses RLS by design, which is required to create policies and seed data.
Generated types
Supabase generates a Database type from your schema. Pass it to SupabaseDatabaseAdapter for end-to-end type safety:
// @noverify
import type { Database } from "@my-app/supabase";
import { SupabaseDatabaseAdapter } from "@stndrds/adapter-supabase";
import { MeilisearchSearchAdapter } from "@stndrds/adapter-meilisearch";
const search = new MeilisearchSearchAdapter({
host: process.env.MEILISEARCH_HOST ?? "",
apiKey: process.env.MEILISEARCH_API_KEY ?? "",
indexPrefix: "myapp",
});
const adapter = new SupabaseDatabaseAdapter<Database>(supabase, { search });Generate types with the Supabase CLI whenever you add a migration:
supabase gen types typescript --local > src/types/database.types.tsThe search option in SupabaseDatabaseAdapter is required when you use Meilisearch. Omit it only if you disable search entirely in SchemaModule.forRoot.