Skip to content

9. Implement Row Level Security Using Drizzle Kit

Date: 2025-10-28

Status

Proposed

Context

During the Neon database migration (ADR 0008), we decided to extract Row Level Security (RLS) implementation from the initial migration scope to reduce complexity. The current approach documents three Supabase RLS policies in docs/operations/neon-rls-follow-up.md, but these are defined as raw SQL rather than version-controlled, type-safe code.

Prisma does not support RLS policy definitions, requiring developers to manage policies separately through raw SQL migrations. This creates maintainability challenges and loses the benefits of type safety and IDE support.

Decision

Use Drizzle Kit for RLS policy definition and management alongside our existing Prisma setup.

Why Drizzle Kit:

  1. Declarative RLS: Define policies using pgPolicy and crudPolicy helpers directly in TypeScript
  2. Type Safety: Policies are type-checked and validated at development time
  3. Migration Support: Drizzle Kit generates SQL migrations for policies, roles, and grants
  4. Neon Integration: Built-in crudPolicy helper optimized for Neon RLS with Firebase Auth
  5. Version Control: Policies live in code alongside schema definitions

Implementation Approach:

  • Keep Prisma for data access and type generation
  • Add Drizzle schema definitions for RLS policies only
  • Export Supabase policies and convert to Drizzle’s declarative format
  • Use Neon serverless driver over HTTP with Firebase JWT tokens
  • Generate and apply migrations using drizzle-kit

Alternatives Considered:

  • Raw SQL in Prisma migrations: No type safety, difficult to maintain
  • Supabase client libraries: Vendor lock-in, doesn’t work with Neon
  • Full migration to Drizzle: Too disruptive; Prisma works well for data access

Consequences

Benefits

  • Type Safety: Policies are TypeScript code, catching errors at development time
  • Maintainability: Policies versioned in Git with clear diffs
  • Developer Experience: IDE autocomplete and validation for policy definitions
  • Migration Safety: Drizzle Kit generates SQL migrations that can be reviewed before applying

Risks & Mitigations

  • Dual ORM Setup: Managing both Prisma and Drizzle increases complexity
    • Mitigation: Use Prisma for data access, Drizzle only for RLS schema/migrations
  • Learning Curve: Team needs to learn Drizzle’s RLS API
    • Mitigation: Start with simple policies, reference Neon’s Drizzle RLS guides
  • Firebase Integration: Must use HTTP mode for Neon RLS, not WebSocket
    • Mitigation: Document clearly; HTTP required for JWT validation

Migration Tasks

  1. Install Drizzle Kit and create drizzle.config.ts
  2. Export existing Supabase RLS policies using pg_policies query
  3. Create Drizzle schema with policy definitions using pgPolicy/crudPolicy
  4. Generate migrations using drizzle-kit generate
  5. Test policies in Neon staging with Firebase Auth tokens
  6. Apply to production and monitor for authorization errors