Tips and best practices for record IDs
This page contains a number of tips and best practices when working with record IDs in SurrealDB.
Why choose the right record ID format
Choosing an apt record ID format is especially important because record IDs in SurrealQL are immutable. Take the following user records for example:
Each of these user records will have a random ID, such as user:wvjqjc5ebqvfg3aw7g61. If a decision is made to move away from random IDs to some other form, such as an incrementing number, this will have to be done manually.
The final query returning just the IDs shows that they have been recreated with new IDs.
However, record IDs are also used as record links and to create graph relations. If this is the case, more work will have to be done in order to recreate the former state.
The following example shows five user records, which each have a 50% chance of liking each of the other users.
Finding out the current relational state can be done with a query like the following which shows all of the graph tables in which a record is located at the in or out point. The ? is a wildcard operator, returning any and all tables found at this point of the graph query.
Surrealist's graph visualization view can help as well.

With this in mind, here are some of the items to keep in mind when deciding what sort of record ID format to use.
Meaningful sortable IDs are faster to query
Records are returned in ascending record ID order by default. As the following query shows, a SELECT statement on a large number of user records with random IDs will show those with record identifiers starting with a large number of zeroes. While the IDs are sortable, the IDs themselves are completely random.
For a large number of records, pagination can be used to retrieve a certain amount of records at a time.
As record ranges are very performant, consider moving any fields that may be used in a WHERE clause into the ID itself.
In the following example, a number of user records are created using the default random ID, plus a num field that tracks in which order the user was created.
As the output from the SELECT statements show, a WHERE clause is needed to find two users starting at a num of 50, as START 50 starts based on the user of the record ID, which is entirely random.
Using a ULID in this case will allow the IDs to remain random, but still sorted by date of creation.
Not only is the START 50 LIMIT 2 query more performant, but the entire num field could be removed if its only use is to return records by order of creation.
Move exact matches in array-based record IDs to the front
Take the following event records which can be queried as a perfomant record range.
The ordering of the ID in this case is likely not ideal, because the first item in the array, a datetime, will be the first to be evaluated in a range scan. A query such as the one below on a range of dates will effectively ignore the second and third parts of the ID.
Instead, the parts of the array that are more likely to be exactly matched (such as user:one and "debug") should be moved to the front.
Using this format, queries can now be performed for a certain user and logging level, over a range of datetimes.
Auto-incrementing IDs
While SurrealDB does not use auto-incrementing IDs by default, this behaviour can be achieved in a number of ways. One is to use the record::id() function on the latest record, which returns the latter part of a record ID (the '1' in the record ID person:1). This can then be followed up with the type::record() function to create a new record ID.
When dealing with a large number of records, a more performant option is to use a separate record that holds a single value representing the latest ID. An UPSERT statement is best here, which will allow the counter to be initialized if it does not yet exist, and updated otherwise. This is best done inside a manual transaction so that the latest ID will be rolled back if any failures occur when creating the next record.
Record IDs are record links
As a record ID is a pointer to all of the data of a record, a single record ID is enough to access all of a record's fields. This behaviour is the key to the convenience of record links in SurrealDB, as holding a record ID is all that is needed for one record to have a link to another.
When using a standalone record ID as a record pointer, be sure to use the record ID itself.
The output of the above query is just the id field on its own, as the $record parameter is an object with an id field, not the id field (the pointer) itself.
To rectify this, id.* can be used to follow the pointer to the entire data for the record.