Previously: In Drizzle ORM Setup and Basic Testing, we set up Drizzle with drizzle-orm-test and created basic tests. Now let's add RLS policies and test them with type-safe queries.
Row-Level Security (RLS) is critical for multi-tenant applications, but testing it traditionally requires manual context switching and raw SQL. With drizzle-orm-test, you get automatic context management—just set the user context and use standard Drizzle queries.
In this lesson, you'll add RLS policies to your pets schema and test them with Drizzle by switching between user contexts.
Prerequisites
See Prerequisites. Requires: Complete Drizzle ORM Setup and Basic Testing.
Why Test RLS with Drizzle?
RLS testing verifies that users only access their own data. drizzle-orm-test makes this seamless by automatically applying context (role, user ID, JWT claims) before each query. You write normal Drizzle queries, and the context is handled for you.
Updating the Schema
First, update src/schema.ts to include userId:
Adding RLS Policies
Add user_id column and RLS policies that depend on the pets_table from the previous lesson:
Edit deploy/pets_rls.sql:
Testing RLS with Drizzle
Now we'll test the RLS policies we added via pgpm add pets_rls. Since the table and policies are managed by pgpm migrations, our test setup is much simpler—we just need to seed test data.
Create __tests__/drizzle-rls.test.ts:
Key pattern: We use pg.beforeEach()/afterEach() for transaction isolation (keeping tests independent), but db.setContext() and drizzle(db.client) for RLS testing. This combination ensures:
- Data seeded by
pg(superuser) bypasses RLS and is visible to all tests - Transaction rollbacks via
pg.afterEach()keep each test isolated - RLS policies are enforced when using
dbwithsetContext()
Using Watch Mode for Rapid Testing
For faster feedback as you write tests, use watch mode. First, initialize git if you haven't already:
Then run tests in watch mode:
Watch mode automatically re-runs tests when you save changes to your TypeScript files. This gives you instant end-to-end feedback as you develop, helping you catch issues immediately and iterate quickly on your RLS policies and test cases.
Testing Authenticated User Access
Add tests for authenticated users managing their own pets:
Testing Update and Delete Operations
Test that users can only modify their own pets:
Run the tests:
Context Switching Between Tests
The power of drizzle-orm-test is seamless context switching. Each test can authenticate as a different user:
Real-World Example
Want to see Drizzle tests running in production CI? Check out the drizzle-test-suite repository—a comprehensive example with working GitHub Actions workflows.
Key Takeaways
- pgpm migrations manage schema - Use
pgpm addfor tables and policies instead of inline SQL pgclient - Use for superuser operations: seeding data and transaction isolation withbeforeEach()/afterEach()dbclient - Use for RLS testing withsetContext()to switch roles and users- setContext() sets authentication context for all subsequent Drizzle queries
- Automatic context management - drizzle-orm-test applies context before each query
- Standard Drizzle API - no special RLS methods needed
- Type-safe RLS testing - use Drizzle's query builder for everything
- Transaction isolation via
pg.beforeEach()/afterEach()ensures tests are independent
What's Next
You've learned how to test RLS policies with Drizzle ORM using automatic context management. The pattern is simple: set context with setContext(), then use standard Drizzle queries. The RLS policies are enforced automatically.
For advanced scenarios like multi-connection testing, cross-user visibility, and complex policies, see the drizzle-orm-test documentation.
