Document Identifier Generation
-
A document identifier (document ID) is a unique string associated with a document.
It is globally unique in the scope of the database - no two documents in the same database can have the same ID. -
This article focuses on the different Document ID Types available in RavenDB and when to use each one.
Additional explanation is available in Working with document identifiers.
To create a document from the Studio, see Create new document. -
In this article:
Overview
ID types
RavenDB supports several document ID types, where the ID string can be generated in different ways:
-
Defined by the user:
You explicitly specify the document ID. -
Generated by the server:
The server generates the document ID based on the ID string format you provide when creating the document. -
Generated by the client (from a range provided by the server):
The server assigns a range of IDs to the client upon request.
The client then uses that range to generate document IDs locally within the session. -
Generated from a Map-Reduce index output:
The ID is generated by the server when saving map-reduce results as artificial documents.
ID Structure
Document IDs typically consist of three parts:
the collection prefix, a slash ('/') as the default separator, and a unique suffix.
For example: users/123-A (HiLo ID), or users/000000000001-A (Server-side ID).
This structure is common but not mandatory:
- RavenDB does not require the ID to include a collection prefix.
- The default slash separator (
/) can be customized for HiLo IDs and Identity IDs. => see how below....
ID Limitations
The following limitations apply to document IDs:
- Maximum length:
512bytes (in UTF-8) - Document IDs cannot end with the following reserved characters:
/- reserved for Server-side ID generation|- reserved for Identity ID generation
Document IDs:
Semantic ID
-
Generated by:
The user -
Description:
- The semantic ID is assigned by you when creating the document (using the Client API or from the Studio),
and not generated by the server. It’s therefore your responsibility to ensure that each ID is unique. - Creating a new document with an existing semantic ID will overwrite the existing document.
- The semantic ID is assigned by you when creating the document (using the Client API or from the Studio),
-
When to use:
Use a semantic ID when you want the document’s identifier to convey meaning,
to reflect what the document represents. -
Example:
- Documents that use an email address as a unique identifier in the Users collection:
users/ayende@ayende.comusers/john@john.doe
This makes the ID both globally unique and instantly meaningful.
It is clear which user the document represents.
- IDs that describe the document’s contents:
accounts/591-192/txs/2025-11-12
Implying that the document holds all the transactions for account 591-192 on November 12th, 2025.support-tickets/INV-88411
A support ticket related to invoice 88411.
- Documents that use an email address as a unique identifier in the Users collection:
- Semantic_id
- Semantic_id_overload
using (var session = store.OpenSession())
{
// Specify the semantic ID in the entity's Id property
var user = new User { Name = "John", Id = "users/john@john.doe" };
session.Store(user);
session.SaveChanges();
// The document will be saved with the ID you specified: "users/john@john.doe"
}
using (var session = store.OpenSession())
{
var user = new User { Name = "John" };
// Specify the semantic ID when calling Store()
session.Store(user, "users/john@john.doe");
session.SaveChanges();
// The document will be saved with the ID you specified: "users/john@john.doe"
}
GUID
-
Generated by:
The server -
Description:
- If you don’t specify a document ID when creating the document,
the server will generate a globally unique identifier (GUID) for the new document. - Although this is a simple way to generate a document ID, GUIDs are not human-friendly
and make debugging or troubleshooting more difficult. This approach is generally less recommended.
- If you don’t specify a document ID when creating the document,
-
When to use:
Use this only when you don’t care about the document ID and don’t need to trace it in logs, tools, or support. -
Example:
A GUID as a document ID:
50bbe329-6258-4634-be24-2f013d7174cd
- GUID_id
- GUID_id_overload
using (var session = store.OpenSession())
{
// Set the entity's Id to string.Empty
var user = new User { Name = "John", Id = string.Empty };
session.Store(user);
session.SaveChanges();
// The server will generate a GUID-based ID, e.g. "50bbe329-6258-4634-be24-2f013d7174cd"
}
using (var session = store.OpenSession())
{
var user = new User { Name = "John" };
// Specify string.Empty when calling Store()
session.Store(user, string.Empty);
session.SaveChanges();
// The server will generate a GUID-based ID, e.g. "50bbe329-6258-4634-be24-2f013d7174cd"
}
Server-side ID
-
Generated by:
The server -
Description:
- When you create a document and provide an ID string that ends with a slash (
/),
the server will generate the full document ID for you. - The server handling the request increments its last document etag and appends it,
along with the server's node tag, to the string you provided. - Since the etag reflects any document change (add, update, delete),
the generated server-side IDs are always increasing but not guaranteed to be sequential.
- When you create a document and provide an ID string that ends with a slash (
-
When to use:
- Use the server-side ID when you don't care about the exact ID given to a newly created document.
- Recommended when creating many documents (e.g., during bulk insert),
as this method has the least overhead and requires minimal work from the server.
-
Example:
- On a server running on node 'A':
- Creating the first document with
users/=> results in document ID:users/0000000000000000001-A - Creating a second document with
users/=> results in document ID:users/0000000000000000002-A
- Creating the first document with
- On a server running on node 'B':
- Creating a third document with
users/=> may result in:users/0000000000000000034-B - Note: node tag 'B' was appended to the ID generated because the request was handled by node 'B'.
Since each server has its own local etag, the numeric part of the ID is not necessarily sequential (or unique) across the nodes in the database group, as can happen when documents are created in parallel on multiple nodes during network partitions or failover.
- Creating a third document with
- On a server running on node 'A':
-
Note:
If you manually generate a document ID with a pattern that matches the server-side generated IDs,
RavenDB will not check for that and will overwrite the existing document.
The leading zeros in server-side generated IDs help reduce the risk of such accidental collisions.
- server_side_id
- server_side_id_overload
using (var session = store.OpenSession())
{
// Set the entity's Id to "users/"
var user = new User { Name = "John", Id = "users/" };
session.Store(user);
session.SaveChanges();
// The server will generate a server-side ID, e.g. "users/0000000000000000001-A"
}
using (var session = store.OpenSession())
{
var user = new User { Name = "John" };
// Specify "users/" when calling Store()
session.Store(user, "users/");
session.SaveChanges();
// The server will generate a server-side ID, e.g. "users/0000000000000000001-A"
}
Identity ID
-
Generated by:
The server -
Description:
- When you create a document and provide an ID string that ends with a pipe symbol (
|),
the server will generate an identity ID. - The server replaces the pipe with a separator character (slash (
/) by default) and appends
an always-incrementing number. - Unlike the server-side ID, identity numbers are guaranteed to be globally unique across all nodes
in the database group.
- When you create a document and provide an ID string that ends with a pipe symbol (
-
When to use:
Use an identity ID only if you truly need document IDs that are incrementing.
For example, when generating invoice numbers or to meet legal or business requirements.Using an identity guarantees that IDs will increment, but doesn't guarantee that the sequence will be gapless. Gaps may occur if documents are deleted or if a transaction fails after incrementing the counter.
For example:companies/1,companies/2,companies/4... -
Example:
- On a server running on node 'A':
- Creating the first document with
users|=> results in document ID:users/1 - Creating a second document with
users|=> results in document ID:users/2
- Creating the first document with
- On a server running on node 'B':
- Creating a third document with
users|=> results in document ID:users/3
- Creating a third document with
- On a server running on node 'A':
-
Note:
-
Identity ID generation comes with a real cost.
In a cluster, where the database is replicated across multiple nodes, the nodes must coordinate to ensure the same identity ID isn’t generated on two nodes. This coordination requires network round-trips. -
Moreover, if the server cannot reach the majority of nodes in the database group,
saving the document will fail because the next identity value cannot be generated. -
All other ID generation methods continue to work even when the server is disconnected from the cluster.
So unless you specifically require incremental IDs, it’s better to use a different ID generation strategy.
-
-
Customizing the separator character:
The separator character used in the identity IDs can be customized.
Learn more in Customizing the separator character. -
Customizing the identity number:
The numeric part of an identity ID is an always-incrementing value managed by the server.
You can modify the latest identity number used for a given prefix (typically a collection name) in the following ways.
The server will base the next generated identity ID on the updated value you provide.- From the Client API:
Use the NextIdentityForOperation to increment the latest identity number.
Use the SeedIdentityForOperation to explicitly set its starting value. - From the Studio:
Go to the Identities view to view or edit the latest identity number for any prefix.
- From the Client API:
- identity_id
- identity_id_overload
using (var session = store.OpenSession())
{
// Set the entity's Id to "users|"
var user = new User { Name = "John", Id = "users|" };
session.Store(user);
session.SaveChanges();
// The server will generate an identity ID, e.g. "users/1"
}
using (var session = store.OpenSession())
{
var user = new User { Name = "John" };
// Specify "users|" when calling Store()
session.Store(user, "users|");
session.SaveChanges();
// The server will generate an identity ID, e.g. "users/1"
}
HiLo algorithm ID
-
Generated by:
The client (from a range provided by the server) -
Description:
- The HiLo algorithm allows generating document IDs on the client side.
- The client requests a range of IDs from the server,
and the server ensures that this range is reserved exclusively for that client. - Different clients receive different, non-overlapping ranges.
- The client can then safely generate IDs locally within the given range,
without further coordination with the server. - For a more detailed explanation, see HiLo Algorithm.
-
When to use:
Use HiLo when you want to create a document and immediately use its ID within the same transaction,
without needing an additional server call to fetch the ID. -
Example:
people/128-A,people/129-B -
Customizing the separator character:
The separator character used in the HiLo document IDs can be customized.
Learn more in Customizing the separator character.
- HiLo_id
using (var session = store.OpenSession())
{
// Do not set the Id property of the entity
var user = new User { Name = "John" };
// Pass only the entity to Store(), without specifying an ID
session.Store(user);
// The ID is already available here because the client holds a reserved range from the server
var documentId = user.Id;
session.SaveChanges();
// The document will be saved with the ID assigned by the session, e.g. "users/1-A"
}
Artificial document ID
-
Generated by:
The server -
Description:
- The output of a Map-Reduce index can be saved as artificial documents in a new collection.
- Their IDs are generated automatically by the server.
Each ID consists of a prefix, which is the name of the output collection you specify,
followed by a hash of the reduce key that you cannot control. - For a more detailed explanation, see Artificial Documents.
-
When to use:
Use artificial documents when you need to further process Map-Reduce index results, for example:- Creating a recursive Map-Reduce index over the resulting artificial documents.
- Running ETL tasks or Subscriptions on the resulting artificial documents collection for further processing.
-
Example:
MonthlyProductSales/1377/0576973199715021
Customizing the separator character
The separator character used in the Identity
and HiLo document IDs can be customized.
By default, the separator is a slash (/), but this can be changed to any other character, except pipe (|).
There are several ways to customize the separator.
It can be configured globally for all databases (server-wide), or per database, overriding the global setting.
From the Studio:
- Configure the separator character globally in: Client configuration (server-wide).
- Override the global setting for a specific database in: Client configuration (per database).
- This will apply to both Identity & HiLo IDs.
From the Client API - using operations:
- Set the separator globally using the PutServerWideClientConfigurationOperation.
- Override the global setting for a specific database using the PutClientConfigurationOperation.
- This will apply to both Identity & HiLo IDs.
// For example, set the separator character for a specific database
var store = new DocumentStore
{
Urls = new[] { "http://localhost:8080" },
Database = "SampleDB"
}.Initialize();
// Customize the separator character to '#' instead of the default '/'
// using the 'PutClientConfigurationOperation' operation
store.Maintenance.Send(new PutClientConfigurationOperation(
new ClientConfiguration { IdentityPartsSeparator = '#' }));;
using (var session = store.OpenSession())
{
// Create document - HiLo ID
// =========================
var user1 = new User() { Name = "John" };
session.Store(user1);
// The session assigns the id immediately
var id = user1.Id; // "users#1-A"
session.SaveChanges();
// The document is saved with ID: "users#1-A"
// Create document - Identity ID
// =============================
var user2 = new User() { Name = "Jane" };
session.Store(user2, "users|");
session.SaveChanges();
// The document is saved with ID: "users#1"
}
From the Client API - using conventions:
- For HiLo IDs, you can also set the separator character using the IdentityPartsSeparator convention on the DocumentStore during initialization.
- Note: Any separator configured later via an operation or from the Studio will override this convention.
- This applies only to HiLo IDs and has no effect on Identity IDs.
// Set the separator character for HiLo ID via conventions
var store = new DocumentStore
{
Urls = new[] { "http://localhost:8080" },
Database = "SampleDB",
Conventions = new DocumentConventions
{
IdentityPartsSeparator = '$',
// ... set any other conventions as needed
}
}.Initialize();
using (var session = store.OpenSession())
{
// Create document - HiLo ID
// =========================
var user1 = new User() { Name = "John" };
session.Store(user1);
// The session assigns the id immediately
var id = user1.Id; // "users$1-A"
session.SaveChanges();
// The document is saved with ID: "users$1-A"
// Create document - Identity ID
// =============================
var user2 = new User() { Name = "Jane" };
session.Store(user2, "users|");
session.SaveChanges();
// The document is saved with ID: "users/1" (uses default separator '/')
}