FR: Add Firestore FieldValue.min() and FieldValue.max() for atomic numeric comparisons
Operating System
not relevant
Environment (if applicable)
not relevant
Firebase SDK Version
not relevant
Firebase SDK Product(s)
Firestore
Project Tooling
not relevant
Detailed Problem Description
✨ Feature Request: Add FieldValue.min() and FieldValue.max() for atomic numeric and timestamp comparisons
Background
Firestore provides several atomic field transformation helpers such as:
FieldValue.increment(n: number)FieldValue.arrayUnion(...elements: any[])FieldValue.arrayRemove(...elements: any[])
These allow developers to update documents without first fetching their current state, which prevents race conditions and reduces read costs.
For example, FieldValue.arrayUnion appends unique elements if they don’t already exist, and all of these helpers automatically create the field if it doesn’t yet exist.
This makes Firestore updates concise, atomic, and efficient.
Problem
There is currently no built-in way to perform atomic minimum or maximum updates on a field.
Developers must:
- Fetch the document,
- Compare the existing value with the new one client-side, and
- Write the result back.
This introduces both extra read costs and race condition risks in concurrent update scenarios.
Proposed Solution
Add two new atomic field transformations:
FieldValue.min(value)
FieldValue.max(value)
These would compare the provided value against the existing field value and update the field to the smaller or larger of the two.
If the field does not exist, Firestore should initialize it with the provided value (consistent with existing FieldValue semantics).
Use Case
I’m building an ecommerce SaaS platform for rental tracking. Each inventory item tracks the timestamp of its last rental activity:
item.lastActivityAt = <timestampMilliseconds>
The system must maintain this field as the latest known return date across thousands of concurrent rental line items.
Example
- SKU with quantity = 2
- One unit is rented this morning for 10 weeks (return date = +10 weeks)
- Another unit is rented this afternoon for 1 week
Without atomic max support:
- The later update (1-week rental) could overwrite the earlier one (10-week rental) if both updates happen close together.
The correct logic should be:
item.lastActivityAt = max(existingValue, newReturnDate)
Currently, this requires a fetch-compare-update cycle for every line item, which is both costly and inefficient:
- ~10,000 line items processed per day → ~10,000 extra reads
- Higher latency and risk of stale writes
Benefits
- Enables atomic
max()andmin()updates similar to increment() - Avoids race conditions in concurrent write scenarios
- Reduces read/write load by eliminating the need to prefetch documents
- Applies broadly across use cases:
- Tracking latest timestamps (
lastSeenAt,lastLoginAt, etc.) - Maintaining running bounds (
minPrice,maxTemperature, etc.) - Recording latest event times (
latestUpdateAt,lastActivityAt, etc.)
- Tracking latest timestamps (
- Keeps Firestore’s expressive and consistent update API style
Suggested API
await docRef.update({
lastActivityAt: FieldValue.max(newReturnDate)
});
Alternative Considered
Using Cloud Functions or a scheduled reconciliation process to serialize updates and compute maxima server-side.
However, this approach introduces latency, cost, and code complexity.
Having a server-side atomic comparison primitive would be faster, cheaper, and more reliable.
Summary
Adding FieldValue.max() and FieldValue.min() would be a natural and powerful extension of Firestore’s atomic update family.
It would dramatically simplify code, reduce operational costs, and prevent concurrency bugs for developers managing high-volume, multi-writer workloads.
Hi @rscotten. I noticed you opened this same feature request on the server sdk (https://github.com/googleapis/nodejs-firestore/issues/2435) also. Could you clarify whether you are asking for this feature on the client sdk (the firebase-js-sdk repository) or the server sdk (the nodejs-firestore repository)? Based on your description is seems that you are asking for this in the client sdk.
One thing I'd like to point out is that the FieldValue.increment, FieldValue.arrayUnion, and FieldValue.arrayRemove operations are not fully "atomic" in the client sdks. This is because if the network connection gets dropped after sending, for example, the FieldValue.increment request to the backend then the acknowledgement of the write may be lost, in which case the client will send the FieldValue.increment again, once network connectivity is restored, resulting in an increment by 2 instead of 1. Obviously, this is rare, but happens occasionally.
If you need true atomicity guaranteed then the only way to do that is via Firestore transactions which allow performing read-modify-write operations atomically.
Hi @dconeybe, I need it both for the client (web browser) SDK and server NodeJS (admin) SDK.
Noted regarding the FieldValue functions not being atomic and to use transactions instead. Thanks for pointing that out. I guess I knew that on some level. I have document listeners with a FieldValue.increment(1) function counting newly created documents. When bulk creating tens of thousands of new documents at once, the resulting count is always short of the actual count, presumably because the cloud function was overloaded and some percentage of FieldValue.increment(1) operations were dropped/lost. I usually have to run a clean-up function to update the actual count, but the FieldValue.increment(1) works well enough for most other use-cases.
After discussing with the team it turns out that this feature, FieldValue.min() and FieldValue.max(), was actually a previous project that almost got completed. The good news is that the backend ostensibly has support for this feature (as can be seen in the proto rpc definition) and, therefore, only client SDK work is remaining.
Please take a look at the link above to the proto rpc definition and read the documentation to ensure that the behavior satisfies your use case.
There is a possibility that we could work on it as a background project, but I can't make any commitments at this point as to when it would be publicly available. I will post updates here though.
@dconeybe thanks for referencing that proto RPC definition. I read through it and that all works for me. Thank you!
hi @dconeybe, hope you're well. Has there been any movement on this?
Hi @rscotten, no, there has not yet been any movement. It is still on our radar though and I've assigned it to @MarkDuckworth, who has agreed to move it forward. I can't provide an ETA but I'd hope to see it released in early 2026.
@dconeybe Awesome and thank you!
Hi @dconeybe & @MarkDuckworth,
I'd like to contribute the client-side implementation of FieldValue.min() and FieldValue.max() for both the firebase-js-sdk and @google-cloud/firestore.
I understand from the discussion that:
- The backend proto already supports these transforms (
minimumandmaximumoperations) - The main work needed is client-side SDK implementation
- The pattern should follow existing transforms like
increment()
I've examined the codebase and believe the changes would primarily involve:
- Adding the two public static helpers to
FieldValueclass - Wiring them through the existing serializer (following the
incrementpattern) - Adding comprehensive unit and integration tests
- Updating TypeScript definitions and documentation
Could you confirm if you're open to an external contributor picking this up? If so, I can open a PR in the next few days with the implementation.
Also, a few clarifying questions:
- Are there any specific design considerations or edge cases I should be aware of?
- Should the implementation support both numbers and timestamps (as indicated in the proto)?
- Are there any existing WIP branches or design docs I should review?
Thank you for considering this contribution!
Best regards, Aditya