• Start

Authorization

Permissions & row-level security

How SurrealDB's PERMISSIONS clause on tables and fields controls create, select, update, and delete, including per-record and field-level rules using $auth.

SurrealDB lets you declare permissions alongside your schema so access is enforced in the database, not only in application code. You attach a PERMISSIONS clause to DEFINE TABLE and DEFINE FIELD to describe which operations are allowed under which conditions.

These clauses apply to record users and to guests when guest access is enabled. System users are not restricted by table or field PERMISSIONS, using roles instead.

On a table, omitting PERMISSIONS results in a PERMISSIONS NONE in the actual statement passed to the database: record users cannot SELECT, CREATE, UPDATE, or DELETE records in that table until you grant access. PERMISSIONS FULL allows all four operations.

Field permissions default the other way. A field without an explicit clause is stored as PERMISSIONS FULL. The table is the main access gate, while field permissions only narrow further when you need to (for example hiding a password). With FULL, a field follows the table's rules without adding its own.

For each table, you set independent rules for create, select, update, and delete. Each clause is a SurrealQL expression that must succeed for that operation to proceed; if it fails, the operation is rejected for the affected records. Field-level permissions refine this: you can constrain select, create, and update on individual fields—useful for sensitive data that should not be readable or writable under the same rules as the rest of the record.

What the wider industry calls row-level security is implemented here by writing expressions that depend on the authenticated context. The $auth variable holds the current identity and claims after sign-in, so you can compare it to fields on the record (for example owner = $auth.id) and ensure each user only sees or changes their own data.

DEFINE TABLE order SCHEMALESS
	PERMISSIONS
		FOR select
			WHERE customer = $auth.id
		FOR create
			WHERE customer = $auth.id
		FOR update, delete
			WHERE customer = $auth.id
;
DEFINE FIELD internal_note ON order TYPE string
	PERMISSIONS
		FOR select FULL
		FOR update WHERE $auth.role = 'admin'
;

Together, table- and field-level PERMISSIONS give you flexible authorisation without duplicating policy in every client. For full syntax and options, see DEFINE TABLE and DEFINE FIELD.

Was this page helpful?