Engenharia · 28 de agosto de 2026

UUID v4 vs v7 — qual escolher em 2026

UUID v7 é o novo padrão para chaves primárias de banco de dados, mas v4 ainda é a escolha certa para tokens de segurança. Como escolher, com comparação lado a lado e benchmarks.

Por 15 anos, UUID v4 foi a única resposta. Identificadores aleatórios de 128 bits, gerados no seu navegador, copiados e colados em uma coluna de banco de dados, usados em todo lugar. Funcionou. Então em 2024, RFC 9562 padronizou v7, e a conversa mudou.

A versão curta: use v7 para novas chaves primárias de banco de dados, use v4 para tokens de segurança e IDs de sessão. Abaixo está o motivo.

O que um UUID realmente é

Um UUID é um identificador de 128 bits, geralmente escrito como 32 caracteres hexadecimais separados por traços: 550e8400-e29b-41d4-a716-446655440000. Os traços são cosméticos; os bytes são o que importa. Os 128 bits dão a você 2¹²⁸ valores possíveis — cerca de 340 undecilhões. Você não vai ficar sem.

O número da versão (o primeiro dígito após o segundo traço — 4 em 550e8400-e29b-**4**1d4-a716-446655440000) diz como o UUID foi gerado. Essa é a parte que importa.

UUID v4: puramente aleatório

UUID v4 é o que a maioria das pessoas quer dizer quando diz “UUID”. 122 dos 128 bits são aleatórios, os outros 6 codificam a versão e a variante. A aleatoriedade é todo o ponto — não há padrão para explorar, não há como adivinhar o próximo ID, não há correlação temporal.

Gere um em qualquer navegador moderno:

crypto.randomUUID() // → "550e8400-e29b-41d4-a716-446655440000"

É lindamente simples. Também é, como se descobriu, péssimo para bancos de dados.

O problema é a indexação B-tree. Uma B-tree é a estrutura de dados por trás da maioria dos índices (Postgres, MySQL, SQLite, MongoDB). Ela mantém os dados ordenados para que consultas por intervalo sejam rápidas e inserções vão para aproximadamente o mesmo local no disco. Quando você insere um UUID aleatório, o banco de dados tem que colocá-lo em algum lugar no meio da árvore — cada inserção se torna uma I/O aleatória. Com milhões de linhas, isso destrói o throughput de escrita.

A correção histórica foi “use UUID v4 mas com ordenação sequencial” — exceto que v4 é, por definição, aleatório. As pessoas contornaram isso (o UUID_TO_BIN(..., 1) do MySQL troca os bits de tempo para frente). RFC 9562 fez o contorno se tornar o padrão.

UUID v7: ordenado por tempo

UUID v7 coloca um timestamp de precisão milissegundo nos bits altos e aleatoriedade nos bits baixos:

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|                           unix_ts_ms                          |
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|          unix_ts_ms           |  ver  |       rand_a          |
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|var|                        rand_b                             |
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|                            rand_b                             |
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘

Os primeiros 48 bits são o timestamp Unix em milissegundos. Os próximos 4 bits são a versão (7). Depois 74 bits aleatórios, depois 2 bits de variante, depois mais 48 bits aleatórios.

O resultado: UUIDs gerados no mesmo milissegundo se ordenam por ordem de inserção. UUIDs gerados depois se ordenam depois. Inserções vão para o lado direito da B-tree, não para o meio. O throughput de写作 sobe de 2 a 10x dependendo do banco de dados.

O benchmark que importa

PlanetScale publicou um benchmark em 2024 que deu números concretos. Com MySQL 8 em um índice de chave primária:

Formato Inserções/s Notas
INT auto-incremento 35.000 Mais rápido, mas vazia informações
UUID v7 18.000 Comparável ao INT para a maioria dos apps
UUID v4 4.500 Inserções aleatórias = divisões de página
UUID v1 (com timestamp) 14.000 Variante mais antiga ordenada por tempo

A diferença de 4x entre v4 e v7 é o custo de fazer I/O aleatória. Para um serviço de alto tráfego, isso se traduz diretamente em dinheiro.

Quando usar v4

UUID v4 ainda é a escolha certa quando o próprio ID é a fronteira de segurança:

  • Tokens de sessão — você não quer que um ID de sessão vaze seu momento de criação. UUID v7 ordena por tempo, o que significa que um atacante que conhece um ID pode adivinhar IDs vizinhos. (A exploração prática é baixa — 74 bits de aleatoriedade ainda são muitos — mas o princípio importa.)
  • Tokens de redefinição de senha — mesmo raciocínio.
  • Chaves de API distribuídas a terceiros — quando o ID é suposto ser inadivinhável, ordenação temporal é uma funcionalidade que você não quer.
  • Qualquer coisa usada como saída CSPRNG — v4 é o que crypto.randomUUID() retorna. Se você está usando o ID para aleatoriedade criptográfica, v4 se encaixa naturalmente.

Quando usar v7

UUID v7 é o padrão correto para:

  • Chaves primárias de banco de dados — esse é o caso de uso principal. A maioria dos novos schemas deve escolher v7.
  • IDs de log de eventos — ordenáveis por tempo sem uma coluna de timestamp separada.
  • IDs de mensagens em filas — ordenação FIFO com unicidade.
  • Identificadores de sistemas distribuídos onde você quer ordenação grossa sem coordenar uma sequência.

Como gerá-los

No navegador, v4 é nativo:

crypto.randomUUID() // v4

Para v7, você precisa de um pequeno polyfill — crypto.getRandomValues mais um prefixo de timestamp. O gerador de UUID no DevSpeedTools produz ambos v4 e v7 no navegador usando crypto.getRandomValues diretamente, para que você possa colar os IDs direto no seu schema sem instalar nada.

No Node.js 22+, o crypto.randomUUID() nativo ainda retorna apenas v4. O pacote npm uuid (v9+) adicionou v7(). Em Python, uuid.uuid7() chegou na 3.14 (lançada em junho de 2025) e agora é a escolha recomendada na documentação da biblioteca padrão. No Postgres, a função gen_random_uuid() ainda retorna v4 — para obter v7, gere client-side e passe-o. MySQL 9 (lançado em 2024) adicionou UUID_V7_BIN() como tipo de primeira classe, e MariaDB seguiu na 11.7. Cloudflare D1, PlanetScale e Supabase todos geram v7 por padrão para novas colunas de chave primária em 2026.

Migrando de v4 para v7

Se você tem uma tabela existente com chaves primárias v4, não precisa migrar. As duas versões coexistem na mesma coluna (o tipo uuid aceita ambos). A melhoria de performance está nas inserções, então só importa se você está adicionando novas linhas. A migração mais simples: comece a gerar v7 para novas inserções, deixe as linhas existentes como v4. Elas ficarão levemente fora de ordem com as novas linhas v7 (já que v4 não tem timestamp), mas o índice estará bem.

Para um schema novo em 2026, v7 é o padrão. O ganho de 4x no throughput de写作 é real, a especificação está estável, todo runtime de linguagem principal tem um gerador v7, e provedores de banco de dados gerenciados estão usando v7 por padrão para novas chaves primárias. Recorra a v4 apenas quando você especificamente precisa de IDs inadivinháveis, livres de correlação temporal.