Sometimes you need a monotonic number: an order line, a ticket counter, or an audit sequence that always moves forward and never hands the same value to two different writers. Sequences are SurrealDB's answer to this: shared, durable generators that work on a single node or in a cluster without needing to construct the logic in application code.
When a sequence helps
Reach for a sequence when:
You care about strictly increasing integers (or a predictable step) rather than opaque identifiers.
Multiple clients or nodes may allocate values at the same time, and collisions would be painful.
You are happy for the value to be numeric and database-owned, not derived from your domain model alone.
If you only need a unique id and ordering is secondary, other patterns (record IDs, ULIDs, hashes) may be simpler. Sequences shine when order and uniqueness are both part of the contract.
Sequences vs. manual incrementing numbers
Auto-incrementing numbers are quick to put together inside a SurrealQL query.
This produces a number that will always increase by 1, and is rolled back during a failed transaction. As such, if fn::get_next() returns the value 4, you can also be certain that values 1, 2, and 3 also exist.
This works well on one server, but it gets awkward in distributed setups: everyone contends on the same record, and you pay for coordination on every allocation.
SurrealDB sequences use a batch idea instead: each node reserves a range of values, hands them out locally, and only talks to shared storage when the range runs out. In practice that means less chatter under load and fewer surprises when you scale out.
You declare a sequence with a name, then ask for the next value when you need it. Here is the shape of the workflow:
Note that a sequence is never rolled back. Each number is guaranteed to be unique and a greater value than any of the ones before, but any sequences used in a failed transaction will simply not be used. This means that a sequence that returns the number 4 is only guaranteed to be the greatest number thus far, but not that the numbers 1, 2, or 3 have been used in any successful transactions.
In other words, ordinary data changes can roll back with a transaction but sequence advances do not.
The following sketch shows the behaviour in which the sequence moves forward even when a transaction aborts, but a counter field does not.
Design with that rule in mind: sequences are for identity and ordering, not for values that must stay in lock step unless you accept gaps.
Optional configurations: batch size, start, and timeout
You can tune how big each reserved batch is, where counting starts, and how long the database should wait when acquiring a new batch. Larger batches mean fewer coordination trips; smaller batches mean less “wasted” headroom if a node stops. A timeout that is too tight can make allocation fail under pressure.
Where to read more
DEFINE SEQUENCE— full statement reference.Sequence functions —
sequence::next/sequence::nextvaland related usage.Transactions — how commits and rollbacks interact with ordinary writes.