# UUID in Manticore: a single ID for the primary database and Manticore

Starting with Manticore Search 28.5.0, you can use a UUID as the document ID. Here we look at how to drop the mapping to numeric IDs, who generates the UUID, and what limitations still remain.

Suppose your product already has the ID `550e8400-e29b-41d4-a716-446655440000` in the primary database. It shows up in events, logs, and API responses. But when you load that same product into Manticore, the application still has to assign it another, numeric ID.

Before Manticore Search 28.5.0, the document ID was an unsigned 64-bit number. A UUID could be stored in a separate string attribute, but that did not make it the document ID. `UPDATE`, `REPLACE`, and `DELETE` still required a numeric `id`.

As a result, you had to keep a mapping between the UUID from the primary database and the numeric ID in the Manticore table. Now you can do without it: an RT table in Manticore can use a UUID as the document ID.

## Why a second ID is a problem

A mapping table between IDs is not exactly complicated, but only as long as the application is loading data and searching. The problems start when documents change.

A worker receives an event with a UUID, finds the matching numeric ID, and only then sends the update to Manticore. Deletion follows the same path. If the mapping record is missing or stale, the wrong document may be updated, or the changes may never reach Manticore at all.

Another option is to turn the UUID into a 64-bit hash. Then the application itself has to account for possible collisions. You can also introduce a separate sequence counter, but then it has to be coordinated across all processes that create documents.

There is another subtle point with numeric IDs, and it appears at the API level. Inside Manticore it is a `uint64`, while SQL shows it as a signed `BIGINT`. Because of that, SQL can return values greater than `2^63-1` as negative numbers, and the client has to convert them carefully. A UUID is passed and returned as a string, so there is no need to worry about signed range or overflow.

`id uuid` solves the problem at the root: the object identifier no longer needs conversion. The same UUID is used in the primary DB, the queue, Manticore, logs, and the external API.

## What a UUID is

[UUID](https://www.rfc-editor.org/rfc/rfc9562.html) is essentially a 128-bit identifier that does not require a central registry to create. In text form, it usually consists of 36 characters: 32 hexadecimal digits and four hyphens.

```text
550e8400-e29b-41d4-a716-446655440000
```

A UUID contains a version and a `variant`. The version defines how the remaining bits are formed. UUIDv4 is based on random or pseudorandom data. UUIDv7 includes a time component and preserves the chronological order of identifiers. In UUIDv8, the placement of the remaining bits is defined by a specific implementation.

The lack of a central registry makes it possible to assign an ID before writing to a shared database. For example, two independent services can create objects in parallel, and a mobile client with no LTE signal can prepare data without a server connection. After synchronization, the object keeps the same identifier.

However, a UUID should not be treated as an absolute guarantee of uniqueness. In practice, that depends on the correctness of the chosen generator. Also keep in mind that a UUID is not a secret and does not replace a password, token, or permission check.

## What changed in Manticore 28.5.0

For an RT table, you can now explicitly set the document ID type:

```sql
CREATE TABLE products_uuid (
    id uuid,
    title text,
    sku string,
    price int
);

INSERT INTO products_uuid (id, title, sku, price)
VALUES (
    '550e8400-e29b-41d4-a716-446655440000',
    'Mechanical keyboard',
    'KB-001',
    149
);
```

After insertion, the same UUID can be used in equality and `IN` filters, as well as in `UPDATE`, `REPLACE`, and `DELETE`. SQL returns the ID as a string. You can also pass an explicit UUID or ask Manticore to generate an ID through the JSON API; we will cover detailed requests and responses in the next article.

If you run `INSERT` again with a UUID that already exists, Manticore rejects it, just as it used to with a numeric ID. Use `REPLACE` to overwrite a document by ID.

Note that the `uuid` type applies only to the document ID. You cannot declare a regular user attribute with the `uuid` type.

## Who creates the UUID

There are two options:

| How the document is written | Who creates the ID | What Manticore does |
|---|---|---|
| The `id` field is provided | The primary DB, a client library, or another system component | Validates the format, version, and `variant`, then stores the UUID in lowercase |
| The `id` field is missing | Manticore | Creates a UUIDv8 and encodes its internal numeric auto-ID into it |

If your application already creates the UUID, you do not need to adapt it to Manticore. The format is standard: five groups of `8-4-4-4-12`. The version can be any from v1 to v8, and the `variant` position must contain `8`, `9`, `a`, or `b`. Case does not matter: you can send the UUID in uppercase, but Manticore will store it in lowercase.

That is where validation ends: Manticore checks the UUID format, but not the quality of the generator. The client library is responsible for the randomness of UUIDv4 and the correct time component in UUIDv7.

Server-side generation works differently. If the `id` field is not provided, Manticore creates a UUIDv8 with its own structure and encodes the built-in numeric auto-ID into it. This is not a random UUIDv4 and it is not a secret value.

A UUIDv8 created by the application will be validated and stored by Manticore as is; the server will not reshape it according to its own scheme.

> Technical note. The full UUID remains the external identifier: Manticore does not replace it with a 64-bit hash and does not require the application to store a mapping table. How the UUID is laid out inside the engine is an implementation detail and does not affect the external contract.

## Where it works

You can use a UUID as the document ID in regular RT tables, RT tables with `engine='columnar'`, and tables in a replication cluster. With such IDs, exact match search, `IN` filters, and the usual document operations are available: `INSERT`, `REPLACE`, `UPDATE`, and `DELETE`.

Keep these limitations in mind:

- the `uuid` type is not suitable for regular attributes: Manticore will reject a declaration such as `guid uuid`;
- in plain, percolate/PQ, and shard tables, UUIDs cannot be used as the document ID;
- an existing table cannot be switched from a numeric ID to a UUID, or back, with `ALTER TABLE`;
- range conditions `<`, `<=`, `>` and `>=`, as well as arithmetic operations on IDs of this type, are not supported;
- the document ID cannot be changed through `UPDATE` - this applies to both UUIDs and numeric IDs;
- for automatic generation, the `id` field must be omitted: the value `0` does not work here as a special marker.

This is easy to forget when porting legacy code. For a numeric RT table, `0` can mean “create the ID automatically.” In a UUID table, you simply need to leave out the `id` field.

UUIDv7 also does not make `id` suitable for time-based filters. You can use it as an external identifier, but Manticore does not yet support queries like `id > ...`.

## Summary

If the UUID already exists in the primary DB, you can now pass it to Manticore together with the document. If the document appears in Manticore first, do not specify `id` and take the generated UUID from the response.

From there, use the same UUID in `UPDATE`, `REPLACE`, and `DELETE`. There is no longer any need to give the document a separate numeric ID and keep a mapping between the two identifiers.

The full contract and current limitations are documented here: [UUID document IDs](https://manual.manticoresearch.com/dev/Creating_a_table/Data_types#UUID-document-IDs). Support for UUID as a document ID appeared in [Manticore Search 28.5.0](/blog/manticore-search-28-5-0/).

In the next article, [a practical guide to using UUIDs as document IDs](/blog/uuid-document-ids-cookbook/), we will step through how to set and generate IDs with SQL and JSON, search, update, replace, and delete documents, and handle errors.
