Generación de UUID en Python, JavaScript y Java
Generá identificadores únicos universales (UUIDs) para claves de base de datos, tokens de sesión y nombrado de recursos en Python, JavaScript y Java.
Overview
Seguramente viste IDs como 550e8400-e29b-41d4-a716-446655440000 en URLs, dumps de base de
datos o logs. Esos son UUIDs — etiquetas de 128 bits pensadas para ser únicas en espacio y tiempo.
Aparecen como claves primarias en sistemas distribuidos, tokens de sesión, nombres de archivos
subidos y básicamente donde un entero auto-incremental no alcanza.
Aprendí la lección v4-vs-v7 por las malas en una tabla de Postgres que llegó a 200M filas. Estábamos viendo que el 40% del I/O se iba en page splits aleatorios — básicamente la base de datos thrashing su propio índice sin razón. Después de cambiar a v7, el throughput de escritura se duplicó prácticamente de la noche a la mañana. La razón es directa — las filas nuevas se agrupan juntas en el B-tree, así que no estás constantemente saltando entre páginas. Para más sobre mantener la performance de base de datos sana, mirá nuestra recipe de database connection pooling.
Últimamente noté que más equipos están migrando a UUID v7 y ULID. Ambos son aproximadamente ordenados por tiempo, así que las inserciones no se esparcen por todo el índice B-tree como pasa con v4 — y en tablas con mucha escritura, eso solo puede ser la diferencia entre un sistema rápido y uno lento. Si estás validando input UUID de fuentes externas, mirá nuestra recipe de data validation para patrones prácticos.
Cuándo Usarlo
Los casos típicos son claves primarias en bases de datos distribuidas, tokens de sesión o API, nombres de archivos o uploads, y fusionar datos de varias fuentes donde los IDs no deben chocar. La generación del lado del cliente es otro caso común: el cliente puede crear un ID antes de llamar al servidor.
Cuándo NO Usarlo
No uses UUIDs en tablas pequeñas y de un solo nodo, donde los enteros auto-incrementales son más simples y rápidos. Evitalos en rutas críticas de performance que no toleren el overhead de un CSPRNG, y no los uses cuando necesitás slugs cortos y legibles para el público.
Solución
Python
import uuid
import ulid
# UUID v4 (random) — el más común
id_v4 = uuid.uuid4()
print(id_v4) # 550e8400-e29b-41d4-a716-446655440000
# UUID v7 (ordenado por tiempo) — mejor para índices de DB
id_v7 = uuid.uuid7() # Python 3.13+
print(id_v7)
# ULID (ordenado por tiempo, lexicográficamente sortable)
id_ulid = ulid.new()
print(id_ulid) # 01ARZ3NDEKTSV4RRFFQ69G5FAV
# Como string para JSON o DB
str_id = str(uuid.uuid4())
JavaScript
import { v4, v7 } from 'uuid';
import { ulid } from 'ulid';
// UUID v4 (random)
console.log(v4()); // 550e8400-e29b-41d4-a716-446655440000
// UUID v7 (ordenado por tiempo) — requiere uuid@10+
console.log(v7()); // 018f3d7e-8... (empieza con timestamp)
// ULID (ordenado por tiempo, lexicográficamente sortable)
console.log(ulid()); // 01ARZ3NDEKTSV4RRFFQ69G5FAV
// UUID random nativo (Node 19+ y navegadores modernos)
console.log(crypto.randomUUID());
Java
import java.util.UUID;
// UUID v4 (random)
UUID idV4 = UUID.randomUUID();
System.out.println(idV4); // 550e8400-e29b-41d4-a716-446655440000
// UUID v7 (ordenado por tiempo) — usá java-uuid-generator o JDK 23+
// Para JDKs más viejos, agregá la librería java-uuid-generator.
// ULID vía librería externa como ulid-java
// String id = Ulid.generate();
Versiones de UUID Comparadas
| Versión | Formato | Ordenable | Ideal para |
|---|---|---|---|
| v4 | Random | No | Uso general, tokens de sesión, mayor soporte |
| v7 | Ordenado por tiempo | Sí | Claves de BD, logs de eventos, mejor localidad de índice |
| v8 | Custom | Configurable | Extensiones específicas de vendor |
| ULID | Tiempo + random | Sí | IDs URL-safe, lexicográficamente sortables |
Explicación
¿Por qué existen los UUIDs? Coordinación, básicamente. Cada nodo puede generar su propio ID sin llamar a un asignador central. Eso es enorme cuando tenés 50 microservicios escribiendo a la misma base de datos — nadie tiene que esperar a un sequence counter, y no necesitás un servicio central de IDs que se convierta en un single point of failure.
v4 se construye con aleatoriedad criptográficamente segura. Es impredecible — genial para secretos, no tanto para bases de datos. Cada insert cae en un lugar random del B-tree, lo que significa page splits y cache misses una vez que la tabla crece lo suficiente. En mi experiencia, esto empieza a doler alrededor de los 10M rows en Postgres — el mileage varía según el hardware.
v7 coloca un timestamp Unix en los bits más significativos y completa el resto con aleatoriedad. Terminás con valores aproximadamente ordenados por tiempo y todavía únicos. El timestamp tiene precisión de milisegundos, así que dos IDs generados en el mismo milisegundo igual difieren en la parte aleatoria.
ULID hace lo mismo pero empaqueta el valor en un string de 26 caracteres en crockford-base32. Es más corto que un UUID en string y seguro para URLs. Personalmente, cambié a ULIDs para IDs públicos hace un tiempo — son más fáciles de copy-pastear en una terminal y nunca tenés que preocuparte por URL encoding.
Como claves primarias, los IDs ordenables mantienen inserciones relacionadas cerca en los índices B-tree. Eso mejora el throughput de escritura y la localidad de caché respecto a valores v4 puramente aleatorios. Si estás cacheando respuestas con clave UUID en el borde, mirá nuestra recipe de caching para estrategias que funcionan bien con claves ordenadas por tiempo.
Variantes
UUID como almacenamiento binario
import uuid
# Convertí un UUID a su representación de 16 bytes para almacenamiento compacto
uid = uuid.uuid7()
binary = uid.bytes # 16 bytes
uid_back = uuid.UUID(bytes=binary)
ULID string para URLs
import { ulid } from 'ulid';
// 26 caracteres, URL-safe, lexicográficamente sortable
const id = ulid();
console.log(`https://api.example.com/items/${id}`);
IDs estilo Snowflake
Si necesitás IDs ordenables de 64 bits, mirá Twitter Snowflake. Depende de un coordinador central o un machine ID para evitar colisiones.
Buenas Prácticas
- Elegí v7 o ULID cuando el ID sea clave primaria de base de datos. El orden por tiempo evita que los índices B-tree se fragmenten.
- Almacená UUIDs como tipos nativos
UUIDoBINARY(16), no como stringsCHAR(36). En MySQL, ir conBINARY(16)en vez de un string de 36 chars corta 20 bytes por fila. En una tabla de 100M filas, son más o menos 2GB solo en storage de IDs. - Generá IDs del lado del cliente solo cuando el cliente los necesite antes de que el servidor responda.
- Validá el formato UUID al parsear input externo.
- Mantené IDs secuenciales internos y exponé UUIDs para identificadores orientados al público.
Errores Comunes
- Elegir UUID v4 como clave primaria sin darse cuenta de la penalización de inserciones aleatorias. Lo vi morder a equipos a escala — el índice se ve bien con 10K filas, pero se desarma con 10M.
- Almacenar UUIDs como strings en vez de tipos binarios compactos. Esto desperdicia espacio y
infla los índices — usá
BINARY(16)o el tipo nativoUUID. - Usar UUIDs en tablas pequeñas y no distribuidas donde los enteros auto-incrementales alcanzan.
- Generar UUIDs en un hot loop sin cachear la instancia del generador.
- Olvidar que UUID v1 filtra direcciones MAC y timestamps — no lo uses para IDs públicos.
See Also
- RFC 4122 — la spec de UUID del 2005. Cubre versiones 1-5 y el formato canónico de string. Vale la pena hojearlo si tenés curiosidad sobre el bit layout.
- ULID spec — reglas de encoding, garantías de monotonicidad y comparación con UUID. El README es sorprendentemente legible.
- Docs del módulo uuid de Python — cubre
uuid4(),uuid7()(añadido en 3.13) y conversión de bytes. - MDN crypto.randomUUID() — generación nativa de v4 en navegadores y Node 19+ vía Web Crypto.
- Recipe de database connection pooling — nuestra guía de connection pooling, que se complementa con claves UUID para performance distribuida.
- Recipe de data validation — nuestros patrones para validar formato UUID y otro input externo.
Preguntas frecuentes
¿Uso UUID v4 o v7 para proyectos nuevos?
Para claves de base de datos, la verdad es que andá con v7 o ULID — el orden por tiempo solo corta la fragmentación de índices, que suele ser el dolor de cabeza más grande. v4 todavía sirve para cosas como tokens de sesión donde no te importa el orden.
¿Son realmente únicos los UUIDs?
Para v4, la probabilidad de colisión es más o menos 1 en 2^122. Que es... un montón. Hablamos de generar billones de UUIDs por segundo durante cientos de años antes de que una colisión siquiera sea plausible. En la mayoría de cargas reales, podés dejar de preocuparte.
¿Puedo usar UUIDs en URLs?
Sí, pero los ULID son la mejor opción acá — son más cortos y URL-safe de fábrica. Si solo tenés v4 o v7, sacá los guiones. No es tan bonito, pero te queda un string de 32 chars que hace el trabajo.
¿Afectan los UUIDs al performance de la base de datos?
UUID v4 causa inserciones aleatorias en B-tree, lo que perjudica el rendimiento de escritura en tablas grandes. UUID v7 y ULID son ordenados por tiempo, así que su performance de escritura es mucho más parecido al de enteros auto-incrementales.
¿Puedo combinar UUIDs con IDs auto-incrementales?
Sí. Un patrón común es un entero auto-incremental como clave primaria interna para el performance de clustering, más un UUID como identificador externo para APIs y URLs.
¿Por qué UUID v1 filtra información?
UUID v1 embebe la dirección MAC de la máquina que lo generó, más un timestamp de 60 bits. Si exponés IDs v1 públicamente, alguien puede fingerprintear la máquina y averiguar cuándo se crearon los IDs — no muy bueno para la privacidad. Quedate con v4 o v7 para cualquier cosa orientada al usuario.
¿Cómo genero UUIDs en un navegador sin dependencias?
Los navegadores modernos y Node 19+ soportan crypto.randomUUID() nativamente. Devuelve un string
UUID v4 sin necesidad de imports:
const id = crypto.randomUUID(); // '550e8400-e29b-41d4-a716-446655440000'
Para v7 o ULID en el navegador, igual vas a necesitar una librería porque la Web Crypto API solo soporta v4.
Recursos Relacionados
Pool de Conexiones a Base de Datos
Configura y ajusta pools de conexiones para maximizar throughput y prevenir el agotamiento de conexiones.
RecipeParsear JSON
Cómo parsear cadenas JSON a estructuras de datos nativas en varios lenguajes de programación.
RecipeValidar y Sanitizar Datos de Input de Usuario
Cómo validar, sanitizar y restringir datos de input de usuario en el boundary de aplicación usando schemas, type checking y librerías de validación.
RecipeCaché y Memoización en Python, JavaScript y Java
Cómo cachear computaciones costosas y respuestas de API usando caches en memoria, LRU, TTL y distribuidos en Python, JavaScript y Java.
RecipeFusionar Archivos JSON
Cómo fusionar múltiples archivos JSON en un solo objeto o array en Python, Java y JavaScript.
PatternPatrón Singleton
Garantiza que una clase tenga una única instancia y proporciona un acceso global a ella. Patrón de diseño creacional para controlar la creación de objetos.