Identificadores aparecem em usuários, pedidos, arquivos, eventos, mensagens, registros de auditoria e sistemas distribuídos. Uma sequência numérica funciona dentro de um único banco, mas exige coordenação quando vários serviços criam dados ao mesmo tempo. O módulo uuid no Python oferece objetos imutáveis de 128 bits que podem ser gerados sem uma autoridade central e transportados como texto, bytes ou inteiro.
Neste guia, você aprenderá quando usar UUIDv4, UUIDv5, UUIDv6 e UUIDv7, por que UUIDv1 pode expor informações, como validar strings, armazenar valores em bancos, ordenar IDs e evitar confundir unicidade com segurança. O artigo complementa nossos conteúdos sobre listas em Python, collections, cópias de objetos, fusos horários e arquivos temporários.
O que é um UUID
UUID significa Universally Unique Identifier. O formato possui 128 bits e costuma ser exibido como 32 dígitos hexadecimais separados por hífens:
550e8400-e29b-41d4-a716-446655440000O objetivo é permitir geração descentralizada com probabilidade extremamente baixa de colisão. Isso não significa uma garantia matemática absoluta em todas as versões e implementações, mas é suficiente para a maioria dos sistemas.
Gerando um UUIDv4
Para um identificador aleatório geral, a opção mais comum é uuid4().
import uuid
identificador = uuid.uuid4()
print(identificador)
print(type(identificador))
print(identificador.version)O objeto retornado é uma instância de UUID, não apenas uma string. O Python gera UUIDv4 com aleatoriedade criptograficamente segura, o que reduz colisões e evita a exposição direta de tempo ou endereço de rede.
Converter para string, bytes e inteiro
Uma mesma instância possui várias representações úteis.
import uuid
valor = uuid.uuid4()
print(str(valor))
print(valor.hex)
print(valor.bytes)
print(valor.int)
print(valor.urn)str() produz o formato padrão com hífens. hex retorna 32 caracteres sem hífens. bytes ocupa 16 bytes. int representa os 128 bits como inteiro. urn produz uma URI como urn:uuid:....
Validando entrada com UUID()
Ao receber um identificador de uma API ou linha de comando, converta-o para UUID antes de usar.
from uuid import UUID
def validar_uuid(texto: str) -> UUID:
try:
return UUID(texto)
except (ValueError, AttributeError, TypeError) as erro:
raise ValueError("UUID inválido") from erroO construtor aceita formatos com hífens, sem hífens, com chaves e com prefixo URN. Depois da conversão, você pode comparar objetos de forma consistente e verificar a versão.
UUIDv1 e privacidade
uuid1() combina tempo, sequência de relógio e um identificador de nó. Historicamente, o nó pode ser derivado do endereço MAC da máquina.
import uuid
valor = uuid.uuid1()
print(valor)
print(valor.node)
print(valor.time)A documentação oficial de uuid alerta que UUIDv1 pode comprometer privacidade ao incluir o endereço de rede. Para novos sistemas, evite v1 quando não houver uma exigência de compatibilidade.
UUIDv3 e UUIDv5: IDs determinísticos
UUIDv3 e UUIDv5 produzem o mesmo identificador para a mesma combinação de namespace e nome. UUIDv3 usa MD5; UUIDv5 usa SHA-1 e normalmente é preferível entre os dois.
import uuid
id_url = uuid.uuid5(
uuid.NAMESPACE_URL,
"https://exemplo.com/produtos/42",
)
print(id_url)Esse comportamento é útil para migrações, importações idempotentes, chaves derivadas de URLs e sincronização entre sistemas. O nome precisa ser canonicalizado: diferenças de maiúsculas, barras finais ou codificação geram UUIDs diferentes.
Namespaces predefinidos
O módulo inclui quatro namespaces conhecidos:
NAMESPACE_DNSpara nomes de domínio;NAMESPACE_URLpara URLs;NAMESPACE_OIDpara OIDs ISO;NAMESPACE_X500para nomes X.500.
Você também pode criar um namespace próprio e reutilizá-lo em toda a organização. Trate esse valor como parte do contrato: trocar o namespace muda todos os identificadores derivados.
UUIDv6: tempo reorganizado
UUIDv6 reorganiza os campos temporais do UUIDv1 para melhorar a localidade em índices de banco. Ele foi adicionado ao módulo no Python 3.14.
import uuid
valor = uuid.uuid6()
print(valor)
print(valor.version)É especialmente útil em sistemas que já dependem da semântica do v1 e precisam de uma ordem binária mais amigável ao banco. Para novos projetos sem legado de v1, o padrão RFC recomenda considerar UUIDv7.
UUIDv7: tempo Unix e ordenação
UUIDv7 incorpora um timestamp Unix em milissegundos nos bits mais significativos e combina o restante com aleatoriedade e mecanismos de monotonicidade.
import datetime as dt
import uuid
valor = uuid.uuid7()
criado_em = dt.datetime.fromtimestamp(
valor.time / 1000,
tz=dt.timezone.utc,
)
print(valor)
print(criado_em)Valores gerados em sequência tendem a ordenar cronologicamente, o que melhora a localidade em índices B-tree em comparação com UUIDv4. Isso não transforma o UUID em um relógio de auditoria confiável; mantenha um campo de data explícito.
Monotonicidade dentro do mesmo milissegundo
Aplicações podem gerar vários UUIDv7 no mesmo milissegundo. A implementação do Python usa um contador para garantir monotonicidade nesse intervalo quando a plataforma não oferece precisão menor.
A ordenação é útil, mas não deve ser confundida com sequência sem lacunas. Processos diferentes, reinicializações e relógios ajustados podem produzir relações que exigem tratamento específico. Use datas e números de sequência separados quando a lógica de negócio exigir ordem total.
UUIDv8: espaço personalizado
UUIDv8 reserva campos para formatos experimentais ou específicos de fornecedor.
import uuid
valor = uuid.uuid8(
0x12345678,
0x9ABC,
0x11223344,
)
print(valor)Os argumentos possuem limites de bits e valores excedentes são truncados. Por padrão, os componentes não são gerados por um CSPRNG. Portanto, v8 não substitui v4 em contextos que precisam de aleatoriedade segura.
UUID NIL e MAX
O Python 3.14 também oferece valores especiais:
import uuid
print(uuid.NIL)
print(uuid.MAX)NIL possui todos os bits em zero e pode representar ausência quando um campo exige 128 bits. MAX possui todos os bits em um e pode servir como sentinela superior. Prefira NULL no banco quando ausência real faz parte do modelo, evitando significados ocultos.
Comparação e ordenação
Objetos UUID são comparados pelo atributo inteiro.
valores = [uuid.uuid7() for _ in range(5)]
ordenados = sorted(valores)
assert ordenados == valoresComparar um UUID com um objeto de outro tipo gera TypeError. Normalize entradas antes de ordenar ou usar como chave.
Armazenamento em banco de dados
As opções comuns são:
- tipo UUID nativo, quando o banco oferece;
- 16 bytes binários;
- texto com 36 caracteres;
- texto hexadecimal com 32 caracteres.
O tipo nativo normalmente fornece validação e funções adequadas. Binário economiza espaço, mas exige cuidado com ordem de bytes e ferramentas de inspeção. Texto é legível, porém ocupa mais espaço.
UUID como chave primária
UUIDs são úteis quando clientes ou serviços precisam criar registros antes de falar com um banco central. Eles também evitam revelar diretamente a quantidade de registros, diferente de IDs sequenciais.
Por outro lado, UUIDv4 insere valores em posições aleatórias do índice e pode aumentar fragmentação. UUIDv7 melhora a localidade, mas continua maior que um inteiro de 64 bits. Meça impacto conforme volume, banco e padrão de consulta.
UUID não é autorização
Um identificador difícil de adivinhar não substitui controle de acesso. Mesmo um UUIDv4 deve ser tratado apenas como nome do recurso.
# incorreto: liberar apenas porque o UUID existe
# correto: validar usuário, organização, papel e recursoAPIs precisam verificar autenticação e autorização em cada operação. Não use UUID como senha, token de sessão ou segredo criptográfico.
Colisões e restrições únicas
A probabilidade de colisão de UUIDv4 é extremamente baixa, mas o banco ainda deve possuir uma restrição UNIQUE ou chave primária. O gerador reduz a chance; a restrição garante a integridade.
Em caso de conflito, gere outro valor e repita a operação de forma controlada. Nunca remova a restrição apenas porque “UUID não colide”.
IDs determinísticos e idempotência
UUIDv5 é excelente para dados que têm uma chave natural estável.
def id_cliente(sistema: str, codigo: str) -> uuid.UUID:
nome = f"{sistema.strip().lower()}:{codigo.strip()}"
return uuid.uuid5(uuid.NAMESPACE_URL, nome)A canonicalização deve ser documentada e testada. Se uma versão futura mudar a regra, identifique a versão no namespace ou em outro campo para não criar duplicatas silenciosas.
Serialização em JSON
O módulo json não converte UUID automaticamente. Transforme em string na borda.
import json
import uuid
registro = {"id": str(uuid.uuid4()), "nome": "Ana"}
texto = json.dumps(registro)
print(texto)Ao ler, reconstrua com UUID(). Em frameworks web, serializers e modelos costumam oferecer suporte nativo.
Uso na linha de comando
Desde o Python 3.12, o módulo pode ser executado diretamente. O Python 3.14 adicionou versões 6, 7 e 8 e a opção de gerar vários valores.
python -m uuid
python -m uuid -u uuid7
python -m uuid -C 10
python -m uuid -u uuid5 -n @url -N https://exemplo.comEsse recurso ajuda em testes, migrações e scripts de implantação sem escrever um programa separado.
RFC 9562 e compatibilidade
O RFC 9562, publicado em 2024, substituiu o RFC 4122. Ele mantém as versões tradicionais e padroniza v6, v7, v8, NIL e MAX.
Sistemas antigos ainda podem exibir a constante RFC_4122 por compatibilidade. O nome permanece, mas o layout atual é especificado pelo RFC mais novo.
Erros frequentes
- Usar UUIDv1 sem considerar privacidade.
- Escolher UUIDv4 e esperar ordenação temporal.
- Usar UUIDv7 como única fonte de data de auditoria.
- Tratar UUID como token de acesso.
- Armazenar texto sem validação.
- Remover a restrição única do banco.
- Usar UUIDv5 sem canonicalizar o nome.
- Adotar UUIDv8 sem especificar o formato.
Boas práticas
- Use v4 para IDs aleatórios gerais.
- Use v5 para IDs determinísticos por nome.
- Considere v7 para bancos que se beneficiam de ordenação temporal.
- Evite v1 em novos projetos por privacidade.
- Armazene como tipo UUID nativo quando possível.
- Mantenha restrições de unicidade.
- Separe identidade de autorização.
- Teste parsing, versão, round-trip e ordenação.
Conclusão
O módulo uuid no Python oferece uma família de identificadores para necessidades diferentes. UUIDv4 fornece aleatoriedade segura, UUIDv5 cria valores determinísticos, UUIDv6 melhora o layout temporal do legado e UUIDv7 combina timestamp Unix com boa localidade para bancos. UUIDv8 fica reservado a formatos personalizados.
A escolha correta depende do contrato: como o ID é gerado, se precisa ordenar, se deve ser reproduzível e quais informações pode revelar. Com validação, tipo adequado no banco, restrições únicas e autorização independente, UUIDs ajudam sistemas distribuídos a criar identificadores sem coordenação central e sem depender de sequências globais.







