Skip to main content
Document Identifier Generation

Document Identifier Generation

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:

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.
  • 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.com
      • users/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.

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"
}

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.
  • 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


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"
}

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 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
    • 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.
  • 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.


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"
}

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 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
    • On a server running on node 'B':
      • Creating a third document with users| => results in document ID: users/3
  • 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.


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"
}

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.


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:


From the Client API - using operations:

// 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 '/')
}