While Pipeline operations offer a rich set of
features, the Rules engine is restricted to recognizing comparison (e.g. >) and logical (e.g. or) filters to ensure
constraint satisfiability and security.
Supported Filter Expressions
For Pipeline operations to be constrained to the bounds set by your rules, it must use logical and comparison operators against constants. The following filter types are recognized by the Rules engine:
- Comparisons:
eq,neq,gt,gte,lt,lte,in,arrayContains. - Logical:
and,or.
Here are some examples:
where(eq("foo", 2))where(lt("foo", 2))documents("/user/1", "/user/2").where(...)
Request Properties
You can continue to use the
request
object to validate authentication and query context, though some properties
available in standard queries are not supported in Pipeline operations.
Supported properties
The new engine continues to support the following properties:
request.auth: Access user uid and token data.request.method: Identifies the operation (For example,get,list).request.path: The path of the resource being accessed.request.time: The server-side timestamp of the request.
Unsupported properties
The request.query properties such as limit, offset, and orderBy are
unsupported for Pipeline operations rule checks due to the complexity of determining these
values in multi-stage queries.
Pipeline stage handling and permissions
There are different pipeline stages that map to specific granular operations in security rules:
allow listpermissions: Triggered bycollection(),collectionGroup(), anddatabase()stages.allow getpermissions: Triggered by thedocuments()stage, which is treated similarly to a batchgetoperation.allow createpermissions: Triggered byinsert()stages, andupsert()stages when creating new documents.allow updatepermissions: Triggered byupdate()stages, andupsert()stages when updating existing documents.allow deletepermissions: Triggered bydelete()stages.allow writepermissions: Applies to all DML operations (insert(),update(),upsert(), anddelete()).- Literals stage: The
literals()stage does not read from the database but can incur costs. To prevent abuse, it must be paired with another stage (likecollection()) that can be verified by rules.
Field modification stages
Rules only operate on stored data and not derived values. If a pipeline includes
stages that modify fields (For example,
add_fields(...),
replace_with(...),
select(...),
remove_fields(...)),
the Rules engine stops applying filter constraints after that stage is
encountered. To ensure that rules works as expected, position your filter stages
(i.e. where) before any stages that can modify the original stored documents.
For example, take the following security rule:
match /databases/{database}/documents {
match /cities/{city} {
// Allow the user to read data if the document has the 'visibility'
// field set to 'public'
allow read: if resource.data.visibility == 'public';
}
}
Denied: This rule rejects the following pipeline because the addFields stage
occurs before filtering to documents where visibility is public:
const results = await db.pipeline()
.collection("/cities")
// Filters after a modification stage are ignored by Rules.
.addFields(constant(1000).as("population"))
.where(eq(field("visibility"), constant("public")))
.execute();
Allowed: This rule allows the following
pipeline because the where(eq(field("visibility"), constant("public"))) stage
occurs before any modification stages:
const results = await db.pipeline()
.collection("/cities")
.where(eq(field("visibility"), constant("public")))
.addFields(constant(1000).as("population"))
.execute();
Data manipulation language stages and security rules
When executing Data manipulation language (DML) stages (insert(), update(),
upsert(), and delete()), Security Rules evaluate permissions differently
than for read queries:
- Per-document rule evaluation: Unlike read pipelines, which require filter expressions up front to constrain the query at planning time, DML operations evaluate security rules against each individual document mutation.
- Rule variables:
request.resource: Contains the proposed document data forinsert(),update(), andupsert()operations.resource: Contains the current document data stored in the database prior to modification (available forupdate(),delete(), andupsert()of existing documents).
System limits and execution behavior with DML
When running DML operations with Security Rules, keep the following system limits and execution behaviors in mind:
The 20-lookup limit on get() and exists()
Firebase Security Rules allows a maximum of 20 document lookups (get() or
exists()) across an entire request.
When a DML pipeline runs outside of an explicit transaction, Cloud Firestore processes document writes in batches. Because each batch executes in its own transaction and documents might be modified concurrently between batches, security rules and document lookups are re-evaluated for each write batch.
Even if your security rules evaluate against a single static document (for example, checking whether a user is an administrator):
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.isAdmin == true;
}
}
}
Each write batch of 10 documents performs a lookup. As a result, after writing
all possible documents, the 20-lookup limit for the request is reached,
and the pipeline fails with a PERMISSION_DENIED error. In addition, each
lookup performed per write batch incurs its own read billing.
Partial success and PERMISSION_DENIED
When executing outside of a transaction, DML operations commit writes in
sequential batches. If a batch fails—either because a document fails a rule
condition or because the 20-lookup limit is exceeded—the pipeline halts and
returns a PERMISSION_DENIED error.
However, batches that were already committed are not rolled back. The database remains in a partially updated state. Because the client receives an error without a list of modified documents, you must query your data to inspect which writes succeeded.
Diagnosing rule failures with Cloud Audit Logs
For security reasons, client-facing PERMISSION_DENIED errors don't disclose
which security rule condition failed or whether the 20-lookup limit was reached.
To diagnose rule evaluation failures, project administrators can inspect
Cloud Audit Logs in the Google Cloud console (under Firestore >
Monitoring or in Logs Explorer) to view detailed EvaluationError
entries.