Simplify RLS with Drizzle
Use Drizzle crudPolicy to manage Row-Level Security with Neon Authorize
What you'll learn
How to simplify Row-Level Security using
crudPolicy
Common RLS patterns with Drizzle
Related docs
Why simplify RLS policies?
Row-Level Security (RLS) is an important last line of defense for protecting your data at the database level. However, implementing RLS requires writing and maintaining separate SQL policies for each CRUD operation (Create, Read, Update, Delete), which can be both tedious and error-prone.
For example
To illustrate, let's consider a simple Todo list app with RLS policies applied to a todos
table. Postgres RLS policies use two types of conditions:
USING
clause — controls which existing rows can be accessedWITH CHECK
clause — controls what new or modified data can be written
note
auth.user_id()
and the role it plays in these policies, see this explanation.Here's how these clauses apply to each operation:
Operation | USING clause | WITH CHECK clause |
---|---|---|
Select | auth.user_id() = user_id | |
Insert | auth.user_id() = user_id | |
Update | auth.user_id() = user_id | auth.user_id() = user_id |
Delete | auth.user_id() = user_id |
And the SQL code would look like this:
As you add new features, you'll need to add more policies to match. This growing complexity can lead to subtle bugs that can be hard to spot in a large schema file filled with SQL statements.
Simplifying RLS with crudPolicy
The crudPolicy
function generates RLS policies by accepting a simple configuration object. Let's break down its usage:
Configuration parameters
The crudPolicy
function accepts these parameters:
role
: The Postgres role(s) to apply the policy to. Can be a single role or an array of rolesread
: Controls SELECT operations:true
to allow all readsfalse
to deny all reads- A custom SQL expression
null
to prevent policy generation
modify
: Controls INSERT, UPDATE, and DELETE operations:true
to allow all modificationsfalse
to deny all modifications- A custom SQL expression
null
to prevent policy generation
When executed, crudPolicy
generates an array of RLS policy definitions covering all CRUD operations (select, insert, update, delete).
The authUid Helper
For user-specific policies, Drizzle provides the authUid
helper function:
This helper:
- Wraps Neon Authorize's
auth.user_id()
function (from the pg_session_jwt extension) - Compares the authenticated user's ID with a table column
- Returns a SQL expression suitable for use in
read
andmodify
parameters
Common patterns
Now that we understand how crudPolicy
works, let's look at two typical ways to secure your tables:
Basic access control
The most common pattern is restricting users to their own data:
Role-based access control
For more complex scenarios, you might want different permissions for different roles:
Example application
Check out our social wall sample application, a simple schema that demonstrates RLS policies with crudPolicy
. It implements a social wall where:
- Anyone can view the wall
- Authenticated users can modify their own posts
Need help?
Join our Discord Server to ask questions or see what others are doing with Neon. Users on paid plans can open a support ticket from the console. For more details, see Getting Support.