Casos ideales y límites: cuándo sí y cuándo no
Todo lo aprendido en el nivel converge en una sola pregunta práctica: ¿para qué es KV y para qué no? Es ideal para configuración, feature flags, tablas de rutas, mapeos y sesiones que se leen mucho más de lo que se escriben. Y es una mala elección —a veces desastrosa— para escrituras frecuentes a una misma clave, contadores y cualquier cosa que exija leer, modificar y escribir de forma segura, porque KV no tiene operaciones atómicas y gana la última escritura. Vemos los casos donde brilla, los antipatrones que hay que evitar, los límites en números y a qué pieza delegar cuando KV no es la respuesta.
Has visto qué es KV, su API, su consistencia eventual y sus mecanismos de tiempo. Toca la síntesis: saber, de un vistazo, si un dato pertenece a KV o a otra pieza. La brújula es siempre la misma proporción —lecturas frente a escrituras— y una sola pregunta sobre la escritura: ¿escribo la misma clave muchas veces, y necesito que cada cambio sea seguro frente a la escritura simultánea de otro? Si escribes poco y toleras el desfase, KV es de las mejores herramientas de la plataforma. Si escribes mucho a la misma clave o necesitas contar sin perder ni una, KV es la elección equivocada, y forzarla produce bugs silenciosos que ningún test local revela.
- Reconocer los casos ideales de KV: configuración, feature flags, mapeos y sesiones de lectura intensiva.
- Identificar los antipatrones: escrituras frecuentes a una clave, contadores y ciclos de leer-modificar-escribir.
- Conocer los límites en números: tamaño de clave, valor y metadata, y el ritmo de escritura por clave.
- Saber a qué pieza delegar cuando KV no encaja: Durable Objects, D1 o R2.
Para qué brilla KV
El caso ideal de KV tiene una firma inconfundible: un dato que se lee muchísimas veces, se escribe rara vez y tolera unos segundos de desfase. Cuando un dato cumple las tres, KV le da algo que casi ninguna otra pieza puede: presencia global a un milisegundo, barata y sin gestionar réplicas.
Configuración
Ajustes de la aplicación que se leen en cada petición y se cambian de vez en cuando. Un get caliente por petición, una escritura ocasional al desplegar.
Feature flags
Banderas que activan o desactivan funcionalidad. Se consultan sin parar y se conmutan pocas veces; que tarden un minuto en propagar no rompe nada.
Mapeos y rutas
Tablas de redirecciones, dominio a tenant, slug a identificador. Datos de referencia que se leen en el camino crítico y cambian despacio.
Sesiones de lectura
Datos de sesión o de token que se leen en cada petición para autorizar, y se escriben solo al iniciar sesión. Lectura intensiva, escritura escasa, con expiración.
El hilo que une los cuatro es la proporción: en todos, las lecturas superan a las escrituras por órdenes de magnitud. KV convierte esa proporción en una ventaja, porque cada lectura repetida se sirve más rápido y más barata desde el caché caliente, mientras la escritura rara no llega a doler. Es, literalmente, para lo que se diseñó.
Para qué NO usarlo
El reverso es igual de nítido, y aquí es donde la mayoría se equivoca. KV es una mala elección siempre que la escritura deja de ser rara o deja de ser segura de perder. Dos antipatrones concentran casi todos los errores.
El primero son las escrituras frecuentes a una misma clave. KV admite del orden de una escritura por segundo y clave; si tu código actualiza la misma clave muchas veces por segundo, no solo va lento, sino que va contra el diseño del sistema. El segundo, más traicionero, son los contadores y cualquier ciclo de leer-modificar-escribir. Como KV no tiene operaciones atómicas ni transacciones, el patrón de leer un número, sumarle uno y volver a escribirlo es una carrera perdida de antemano: entre tu lectura y tu escritura, otro Worker pudo escribir, y su incremento se esfuma sin error.
// ANTIPATRON: un contador sobre KV pierde incrementos en silencio
const n = Number(await env.MI_KV.get("visitas")) || 0;
await env.MI_KV.put("visitas", String(n + 1)); // otra escritura simultanea se pierde
// La forma correcta de contar vive en un Durable Object, que serializa el acceso
// y ofrece atomicidad e identidad unica por objeto.
El drama del contador sobre KV es que funciona perfectamente en tu máquina y en las pruebas: con una sola escritura a la vez, nunca hay carrera. El fallo solo emerge en producción, bajo concurrencia real y de forma intermitente, cuando dos peticiones coinciden. Pierdes incrementos, se corrompen agregados, y el motivo es invisible en los logs. Regla dura: si un dato necesita “leer, modificar y escribir” sin perder nada, no toca KV jamás.
Los límites y a quién delegar
Conviene tener los números en la cabeza para no descubrirlos por sorpresa: una clave admite hasta 512 bytes, un valor hasta 25 MiB, la metadata hasta unos 1024 bytes, y una clave concreta tolera del orden de una escritura por segundo. Cuando un dato choca con alguno de esos muros —o con la consistencia eventual—, la señal no es “fuerza KV”, sino “esta pieza es otra”.
flowchart TB
D{que necesita el dato} --> A[lectura global, escritura rara, tolera desfase]
D --> B[contar, coordinar, leer-modificar-escribir atomico]
D --> C[consultas relacionales, filtros, orden, joins]
D --> E[ficheros grandes o binarios de muchos MB]
A --> KV[Workers KV]
B --> DO[Durable Objects]
C --> D1[D1 SQLite]
E --> R2[R2]
style KV fill:#a6e3a1,color:#11111b
style DO fill:#cba6f7,color:#11111b
style D1 fill:#89b4fa,color:#11111b
style R2 fill:#fab387,color:#11111bEl mapa de delegación es limpio. Lo que exige atomicidad, contadores o coordinación con estado va a un Durable Object, que serializa el acceso y da identidad única. Lo que exige consultas ricas —filtrar, ordenar, unir tablas, contar con exactitud— va a D1, la base SQLite de la plataforma. Los ficheros grandes van a R2, el almacén de objetos sin cargos de egress. KV se queda con su franja: la lectura global, frecuente y tolerante al desfase. Reconocer a cuál pertenece cada dato, en vez de meter todo en el primero que aprendiste, es exactamente lo que separa a quien usa la plataforma de quien la diseña.
La lección que cierra el nivel, y que en realidad abre todo el bloque de almacenamiento que viene después, es que no existe el almacén de datos correcto en abstracto: existe el almacén cuyas garantías coinciden con lo que tu dato de verdad necesita, ni más ni menos. Cada pieza de la plataforma vende una combinación distinta de garantías —consistencia, atomicidad, alcance geográfico, capacidad de consulta, latencia— a un precio distinto, y ese precio no se paga solo en dinero, sino en rendimiento, en complejidad y en las cosas que dejas de poder hacer. KV es la ganga de una garantía muy concreta: lectura omnipresente a coste mínimo, a cambio de renunciar a la consistencia inmediata, a la atomicidad y a la consulta rica. Es baratísimo precisamente porque renuncia a mucho, y es una maravilla para el dato que no echa en falta nada de lo que renunció. El error de raíz —el que produce los contadores rotos, las sesiones incoherentes, los agregados corruptos— no es técnico sino conceptual: consiste en comprar la garantía barata para un dato que necesitaba la cara, y descubrirlo solo cuando la concurrencia de producción destapa la diferencia. La disciplina que hay que cultivar es la inversa y es sencilla de enunciar aunque exija honestidad para aplicarla: antes de elegir dónde vive un dato, escribe qué garantía necesita de verdad. ¿Tolera ver una versión vieja durante un minuto? ¿Puede perder una escritura concurrente sin consecuencias? ¿Alguna vez tendrás que preguntarle algo más complejo que “dame el valor de esta clave”? Las respuestas honestas te encaminan casi siempre a una sola pieza, y cuando esa pieza es KV, has encontrado uno de los tratos más ventajosos de toda la computación en el edge: el mismo dato, en todo el planeta, a un milisegundo, casi gratis. Y cuando no lo es, KV te lo dice a tiempo —con un límite, con un desfase, con un incremento perdido— para que lleves el dato a la pieza que sí sabe cargarlo. Saber leer esa señal, y no la potencia de ninguna herramienta, es el arte de diseñar datos en el edge.
- Clasifica cinco datos de una app real —configuración, contador de visitas, catálogo de productos, sesión de usuario, avatares— y asigna cada uno a KV, Durable Objects, D1 o R2, justificando la garantía que necesita.
- Explica, con un ejemplo concreto de concurrencia, por qué un contador sobre KV pierde incrementos y por qué eso no aparece en las pruebas locales.
- Toma un caso que hoy usa KV para escribir la misma clave muchas veces por segundo y rediséñalo: ¿qué pieza lo resuelve y por qué?
- Recita los límites de KV en números —clave, valor, metadata, ritmo de escritura por clave— y da, para cada uno, un dato que lo violaría.
- Formula la regla de decisión en una sola frase que puedas aplicar antes de guardar cualquier dato, y pruébala contra los cinco datos del punto 1.