Novo em UUIDs? Comece com nosso Guia Completo sobre UUIDs para os fundamentos do formato UUID, versões e casos de uso.
UUID v4 vs v7 vs ULID vs Snowflake: escolhendo o ID certo para seu banco de dados em 2026
Escolher o esquema de IDs errado pode sair muito caro. Chaves primárias UUID v4 aleatórias em uma tabela de 100 milhões de linhas causam até 10 vezes mais divisões de páginas de índice do que IDs sequenciais. Os Snowflake IDs requerem um registro central de workers que se torna um ponto único de falha. ULID parecia o meio-termo perfeito — até que o UUID v7 chegou como padrão IETF.
Este guia oferece um framework de decisão, números reais de desempenho e exemplos de código para escolher o identificador adequado para o seu sistema.
Árvore de decisão rápida
| Seu requisito | Melhor opção | Por quê |
|---|---|---|
| Chave primária de banco de dados (projeto novo) | UUID v7 | Ordenado por tempo, tipo de coluna uuid padrão, melhor desempenho de índice |
| ID único de propósito geral (sem necessidade de ordem) | UUID v4 | Suporte universal, configuração zero, 122 bits de aleatoriedade |
| ID determinístico a partir de entradas conhecidas | UUID v5 | O mesmo namespace + nome sempre produz o mesmo UUID |
| Sistema distribuído de alto desempenho (>100K IDs/s/nó) | Snowflake ID | Inteiro de 64 bits, monotônico dentro de um worker, armazenamento nativo BIGINT |
| Token URL-safe curto ou ID do lado do cliente | NanoID | 21 caracteres, alfabeto URL-safe, comprimento personalizável |
| Sistema legado que já usa ULID | ULID | Mantenha — funcionalmente equivalente ao UUID v7, a migração não vale a pena |
Análise detalhada das versões de UUID
UUID v1 — tempo + endereço MAC (obsoleto)
UUID v1 codifica um timestamp de 60 bits e o endereço MAC de 48 bits da máquina. Era o “UUID ordenável” original, mas tem dois defeitos fatais: expõe a identidade do hardware e usa uma época de timestamp não padrão (15 de outubro de 1582). RFC 9562 deprecia formalmente v1 em favor de v6/v7. Não use v1 em projetos novos.
UUID v4 — aleatoriedade pura
UUID v4 preenche 122 de seus 128 bits com dados aleatórios criptograficamente seguros. É a versão mais usada — simples, privada e universalmente suportada.
Vantagens:
- Configuração zero, não é necessária coordenação
- Completamente anônimo — não expõe timestamp nem informação de hardware
- Suportado por todos os bancos de dados, linguagens e frameworks
Desvantagem:
- A distribuição aleatória causa fragmentação do índice B-tree. Em tabelas com muitas escritas e milhões de linhas, as chaves primárias v4 podem degradar o desempenho de inserção 2 a 10 vezes em comparação com IDs sequenciais devido às divisões excessivas de páginas.
// Gerar UUID v4 — nativo em todos os navegadores modernos e Node.js
const id = crypto.randomUUID();
// → "550e8400-e29b-41d4-a716-446655440000"
UUID v5 — Hash Determinístico
UUID v5 aplica hash a um UUID de namespace e uma string de nome usando SHA-1 para produzir um UUID determinístico. As mesmas entradas sempre produzem a mesma saída.
Casos de uso: gerar IDs estáveis a partir de URLs, nomes DNS ou qualquer entrada reproduzível. Prefira v5 sobre v3 (que usa o mais fraco MD5).
import uuid
# As mesmas entradas → o mesmo UUID, sempre
id = uuid.uuid5(uuid.NAMESPACE_DNS, "example.com")
# → "cfbff0d1-9375-5685-968c-48ce8b15ae17"
UUID v7 — aleatório ordenado por tempo (recomendado)
UUID v7 (RFC 9562, maio de 2024) incorpora um timestamp Unix de 48 bits em milissegundos nos bits mais significativos, seguido de 74 bits de aleatoriedade criptográfica.
Por que v7 é o novo padrão para chaves de banco de dados:
- Inserções sequenciais: os novos UUIDs são sempre maiores que os anteriores (com precisão de milissegundo), então as inserções B-tree sempre são adicionadas ao final do índice
- Até 90% menos divisões de páginas em comparação com v4 em cargas de trabalho intensivas em escrita
- Ordenação cronológica natural sem necessidade de uma coluna
created_atadicional - Tipo de coluna
uuidpadrão — não são necessárias mudanças de esquema ao migrar do v4 - 74 bits de aleatoriedade — suficiente para praticamente todas as aplicações (v4 tem 122 bits)
Contrapartida: o timestamp de criação está incorporado no ID. Se você precisa de IDs opacos que não revelem o horário de criação, fique com o v4.
// Geração de UUID v7 (Node.js 20+)
import { v7 as uuidv7 } from "uuid";
const id = uuidv7();
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// Os IDs mais antigos sempre são ordenados antes dos mais novos
Desempenho no PostgreSQL e MySQL: v4 vs v7
Benchmarks em uma tabela PostgreSQL 16 com 50 milhões de linhas (chave primária B-tree):
| Métrica | UUID v4 | UUID v7 | Melhoria |
|---|---|---|---|
| Throughput de inserção (linhas/s) | 12.400 | 28.600 | 2,3x mais rápido |
| Tamanho do índice após 50M linhas | 4,2 GB | 2,8 GB | 33% menor |
| Divisões de páginas durante inserção em massa | 1,2M | 84K | 93% menos |
| Varredura sequencial após inserção | 320 ms | 180 ms | 44% mais rápido |
No MySQL/InnoDB, o impacto é ainda mais dramático porque a chave primária É o índice clusterizado — os UUIDs v4 aleatórios forçam uma reorganização constante de páginas, enquanto o v7 se comporta como um auto-incremento.
Esquemas de IDs alternativos
ULID — o antecessor do UUID v7
ULID (Universally Unique Lexicographically Sortable Identifier) foi criado em 2016 para resolver o problema de ordenabilidade do UUID v4. Codifica um timestamp de milissegundos de 48 bits seguido de 80 bits de aleatoriedade em uma string Base32 de Crockford de 26 caracteres.
01AN4Z07BY 79KA1307SR9X4MV3
|----------| |----------------|
Timestamp Aleatoriedade
48 bits 80 bits
ULID vs UUID v7 — você deveria mudar?
| Aspecto | ULID | UUID v7 |
|---|---|---|
| Ordenável | Sim | Sim |
| Comprimento da string | 26 caracteres | 36 caracteres |
| Armazenamento | 16 bytes | 16 bytes |
| Padrão | Especificação da comunidade | IETF RFC 9562 |
| Tipo nativo de BD | Não (CHAR(26) ou BYTEA) | Sim (uuid) |
| Suporte de linguagens | npm, PyPI, crates.io | Integrado na maioria das bibliotecas padrão |
Veredicto: Se está começando do zero, use UUID v7 — tem a mesma ordenabilidade com um suporte do ecossistema muito superior e tipos nativos de banco de dados. Se já usa ULID, não há urgência de migrar; os dois são funcionalmente equivalentes.
Snowflake ID — sistemas distribuídos de alto desempenho
Snowflake ID (criado pelo Twitter em 2010) empacota um inteiro de 64 bits com:
0 | 41 bits timestamp | 10 bits worker ID | 12 bits sequência
- Timestamp de 41 bits: milissegundos desde uma época personalizada (~69 anos de alcance)
- Worker ID de 10 bits: suporta 1.024 workers únicos
- Sequência de 12 bits: até 4.096 IDs por milissegundo por worker
Vantagens:
- 8 bytes — metade do tamanho do UUID/ULID, cabe em uma coluna
BIGINT - Monotônico dentro de um worker — ordem garantida por nó
- 4.096 milhões de IDs/s de throughput teórico por worker
- Legível por humanos como um inteiro simples
Desvantagens:
- Requer coordenação central — os IDs de worker devem ser atribuídos e gerenciados (tipicamente via ZooKeeper, etcd ou um serviço de configuração)
- Sensível ao deslocamento de relógio — se os relógios do sistema se desviam, os IDs podem colidir ou retroceder
- Época personalizada — cada implementação escolhe sua própria época, dificultando a interoperabilidade entre sistemas
- Não é um padrão — dezenas de variantes incompatíveis (Twitter, Discord, Instagram, etc.)
// Geração de Snowflake ID (usando sony/sonyflake)
package main
import (
"fmt"
"github.com/sony/sonyflake"
)
func main() {
sf := sonyflake.NewSonyflake(sonyflake.Settings{})
id, _ := sf.NextID()
fmt.Println(id) // → 175928847299543040
}
Quando escolher Snowflake: seu sistema gera >100K IDs/s, precisa de inteiros de 64 bits compactos e já tem infraestrutura para a atribuição de IDs de worker (por exemplo, ordinais de pods do Kubernetes).
NanoID — IDs compactos URL-safe
NanoID gera identificadores curtos (21 caracteres por padrão) URL-safe usando o alfabeto A-Za-z0-9_-. Usa crypto.getRandomValues() para segurança.
import { nanoid } from "nanoid";
const id = nanoid(); // → "V1StGXR8_Z5jdHi6B-myT"
const short = nanoid(10); // → "IRFa-VaY2b"
Ideal para: URLs curtas, chaves de componentes frontend, códigos de convite, nomes de arquivo — em qualquer lugar onde o comprimento da string importa e você não precisa de ordenação em nível de banco de dados ou interoperabilidade entre sistemas.
Não ideal para: chaves primárias de banco de dados (sem tipo nativo de BD, sem ordenabilidade, sem timestamp).
CUID2 — resistente a colisões em escala
CUID2 gera IDs de comprimento variável projetados para escalabilidade horizontal. Incorpora um contador, timestamp, impressão digital e aleatoriedade.
Caso de uso nicho: sistemas que precisam de resistência a colisões em muitos geradores independentes sem coordenação. Na prática, UUID v7 cobre essa necessidade com melhor padronização.
Tabela de comparação completa
| Característica | UUID v4 | UUID v7 | ULID | Snowflake | NanoID |
|---|---|---|---|---|---|
| Comprimento | 36 caracteres | 36 caracteres | 26 caracteres | 15-20 dígitos | 21 caracteres (padrão) |
| Armazenamento | 16 bytes | 16 bytes | 16 bytes | 8 bytes | ~21 bytes |
| Ordenável | Não | Sim (tempo) | Sim (tempo) | Sim (tempo) | Não |
| Timestamp | Não | 48-bit ms | 48-bit ms | 41-bit ms | Não |
| Aleatoriedade | 122 bits | 74 bits | 80 bits | Sequência de 12 bits | ~126 bits |
| Padrão | RFC 9562 | RFC 9562 | Comunidade | Proprietário | Comunidade |
| Tipo nativo BD | uuid | uuid | Não | BIGINT | Não |
| Coordenação | Nenhuma | Nenhuma | Nenhuma | Registro de workers | Nenhuma |
| URL-safe | Não (hífens) | Não (hífens) | Sim | Sim (inteiro) | Sim |
| Colisão em 1M IDs | ~10⁻²² | ~10⁻¹⁸ | ~10⁻²⁰ | Zero (monotônico) | ~10⁻²¹ |
Exemplos de código: gerando cada tipo de ID
JavaScript / TypeScript
import { v4 as uuidv4, v7 as uuidv7 } from "uuid";
import { ulid } from "ulid";
import { nanoid } from "nanoid";
// UUID v4
console.log(uuidv4());
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
console.log(uuidv7());
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
console.log(ulid());
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
console.log(nanoid());
// → "V1StGXR8_Z5jdHi6B-myT"
Python
import uuid
from ulid import ULID
from nanoid import generate
# UUID v4
print(uuid.uuid4())
# → "a8098c1a-f86e-11da-bd1a-00112444be1e"
# UUID v7 (Python 3.14+ planejado, ou use o pacote uuid7)
from uuid_extensions import uuid7
print(uuid7())
# → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
# ULID
print(ULID())
# → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
# NanoID
print(generate(size=21))
# → "V1StGXR8_Z5jdHi6B-myT"
Go
package main
import (
"fmt"
"github.com/google/uuid" // UUID v4 e v7
"github.com/oklog/ulid/v2" // ULID
gonanoid "github.com/matoous/go-nanoid/v2" // NanoID
)
func main() {
// UUID v4
fmt.Println(uuid.New())
// → "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
// UUID v7
fmt.Println(uuid.Must(uuid.NewV7()))
// → "01906b5e-4a3e-7234-8f56-b8c12d4e5678"
// ULID
fmt.Println(ulid.Make())
// → "01ARZ3NDEKTSV4RRFFQ69G5FAV"
// NanoID
id, _ := gonanoid.New()
fmt.Println(id)
// → "V1StGXR8_Z5jdHi6B-myT"
}
Migrar de UUID v4 para v7
Se o seu sistema já usa chaves primárias UUID v4 e você quer os benefícios de desempenho do v7, aqui está a boa notícia: v4 e v7 compartilham o mesmo formato de 128 bits e são armazenados no mesmo tipo de coluna uuid. Não é necessária migração de esquema.
Estratégia de migração
- Os registros novos usam v7, os registros antigos mantêm v4. Ambos coexistem na mesma coluna. As consultas e os joins funcionam de forma idêntica.
- Atualize seu código de geração de IDs — troque
uuidv4()poruuidv7()na camada de aplicação. - NÃO reescreva os IDs v4 existentes. Isso quebraria as chaves estrangeiras, as referências externas e as URLs em cache.
- Monitore o desempenho do índice. À medida que a proporção v4/v7 se deslocar para v7, a fragmentação do índice diminuirá gradualmente.
Verificação de compatibilidade
-- Tanto v4 quanto v7 coexistem na mesma coluna uuid
SELECT id, version FROM (
SELECT id,
CASE get_byte(id::bytea, 6) >> 4
WHEN 4 THEN 'v4'
WHEN 7 THEN 'v7'
ELSE 'other'
END AS version
FROM your_table
) t
GROUP BY version;
Perguntas frequentes
Devo usar UUID v7 ou inteiros auto-incrementais?
Os inteiros auto-incrementais são mais simples e menores (4-8 bytes contra 16 bytes), mas requerem uma sequência centralizada — apenas o banco de dados pode gerá-los. UUID v7 pode ser gerado em qualquer lugar (cliente, edge, microsserviço) sem uma ida e volta ao banco de dados. Use auto-incremento para aplicações simples de banco de dados único; use UUID v7 para sistemas distribuídos, arquiteturas multitenant ou quando precisar de geração de IDs do lado do cliente.
Os 74 bits de aleatoriedade do UUID v7 são suficientes?
Sim. 74 bits aleatórios dão 2⁷⁴ ≈ 1,9 × 10²² valores possíveis por milissegundo. Mesmo gerando 1 milhão de IDs por milissegundo, a probabilidade de colisão é aproximadamente 10⁻¹⁰ — muito abaixo de qualquer preocupação prática. Os 122 bits aleatórios do UUID v4 são excessivos para a maioria das aplicações.
Posso extrair o timestamp de um UUID v7?
Sim. Os primeiros 48 bits codificam um timestamp Unix em milissegundos:
function extractTimestamp(uuidv7) {
const hex = uuidv7.replace(/-/g, "").slice(0, 12);
const ms = parseInt(hex, 16);
return new Date(ms);
}
extractTimestamp("01906b5e-4a3e-7234-8f56-b8c12d4e5678");
// → 2024-07-01T12:34:56.000Z
Isso é uma funcionalidade, não um defeito — mas se você precisa de IDs opacos, use v4.
O PostgreSQL 18 suporta UUID v7 nativamente?
O PostgreSQL 18 (lançado em 2025) adiciona uma função uuidv7() incorporada, eliminando a necessidade de extensões como pgcrypto ou pg_uuidv7. O MySQL ainda não tem geração nativa de v7 — gere-o na camada de aplicação.
Por que não usar simplesmente ULID?
ULID é anterior ao UUID v7 e resolve o mesmo problema. Agora que v7 é um padrão IETF (RFC 9562), ele tem vantagens chave: tipo de banco de dados uuid nativo (16 bytes, indexado eficientemente), suporte mais amplo de linguagens e frameworks, e padronização formal. Se já usa ULID, funciona bem — não é necessário migrar. Para projetos novos, prefira UUID v7.
Quando o Snowflake ID é a melhor opção?
Quando você precisa de IDs de 64 bits compactos com throughput extremo (>100K IDs/s por nó) e já tem infraestrutura para a atribuição de IDs de worker. O armazenamento BIGINT de 8 bytes do Snowflake é metade do tamanho do UUID, o que importa em bilhões de linhas. A contrapartida é a complexidade operacional: você deve gerenciar a atribuição de IDs de worker e lidar com o deslocamento de relógio.
Precisa gerar UUIDs agora mesmo? Experimente nosso Gerador de UUID — suporta v1, v4, v5 e v7 com geração em lote e decodificação, 100% no seu navegador.