Primero separar: servidor, cliente, UI y URL
La primera decisión de arquitectura no es qué librería adoptar, sino reconocer que el estado no es una cosa homogénea: son cuatro clases con naturalezas distintas, y confundirlas origina la mayoría de los bugs de sincronización. Esta lección abre el nivel de cierre del track separando el estado por su dueño y su propósito —servidor como cache de una verdad remota, cliente como dato de dominio propio, UI como apariencia efímera y local, y URL como estado navegable— y asigna a cada clase su herramienta idiomática de 2026. Defiende que esta clasificación, hecha antes que ninguna otra elección, es la decisión de mayor palanca de toda la arquitectura: fija la frontera que jamás se cruza, encoge el estado global a lo que de verdad lo es, y vuelve casi mecánicas las decisiones posteriores sobre librería y disciplina de mutación.
Todo el track desemboca aquí: no en una herramienta más, sino en el criterio para elegir entre todas. Y ese criterio empieza con una decisión que precede a cualquier otra y pesa más que ninguna. No es qué gestor de estado usar, ni qué arquitectura adoptar, ni siquiera qué framework. Es reconocer que la palabra estado nombra cuatro cosas distintas que hemos tratado como una sola durante demasiado tiempo. El dato que traes del servidor, el que posee tu cliente, el que solo describe cómo se ve una vista y el que dice dónde está el usuario en tu app no son variaciones de un mismo problema: son problemas diferentes con dueños diferentes, y cada uno pide una herramienta distinta. Separar esas cuatro clases, antes de escribir una línea de arquitectura, es la decisión de mayor palanca que tomarás en todo el diseño.
- Distinguir las cuatro clases de estado por su dueño y su propósito, no por su forma.
- Asignar a cada clase su herramienta idiomática de 2026 sin mezclarlas en un cajón único.
- Entender por qué la frontera entre servidor y cliente es la que jamás se cruza.
- Justificar por qué esta clasificación es la decisión de arquitectura de mayor palanca.
El estado no es una cosa: son cuatro
Durante años la pregunta de arquitectura se formuló mal: qué gestor de estado adopto. La pregunta presupone que el estado es una sustancia homogénea que un único gestor debe gobernar, y esa premisa es falsa. El estado de una aplicación es una mezcla de cosas con naturalezas incompatibles, y la primera destreza de quien diseña sistemas es dejar de verlas como una sola.
El corte que las separa es de propiedad, la pregunta que ya recorriste en el Nivel 2 y que aquí se vuelve el primer eje: quién posee la verdad de este dato. Si vive en otra máquina y tú solo guardas una copia, no eres su dueño sino su lector, y lo que tienes es una cache que envejece sola. Si lo posee tu cliente —nadie lo cambia a tus espaldas—, tu última escritura es la verdad por definición. Ese primer corte parte el estado en dos mitades tan distintas que apenas comparten problemas.
La mitad que el cliente posee se subdivide por un segundo eje, el propósito. Un dato propio puede ser de dominio —importa a la lógica, lo leen varios módulos, su corrupción sería un bug de datos—, puede ser mera apariencia de una vista —si un desplegable está abierto, qué pestaña interna se ve, dónde está el foco—, o puede describir la ubicación del usuario —el filtro activo, la página, el elemento seleccionado que debería sobrevivir a un enlace compartido—. Tres propósitos que, sumados al servidor, dan las cuatro clases del nivel.
Conviene subrayar que la clase no se lee en la forma del dato. Dos piezas idénticas por fuera —ambas un array de objetos— pueden pertenecer a clases opuestas, porque lo que las separa no es su tipo sino su origen y su dueño.
// Misma forma, clases opuestas: decide el dueno, no el tipo.
type Producto = { id: string; nombre: string };
type Tarea = { id: string; texto: string };
const productos: Producto[] = await traerDeLaApi(); // servidor: copia remota que envejece sola
const tareas: Tarea[] = []; // cliente: el usuario las crea, nadie mas las toca
La forma engaña; el dueño no. Por eso el primer eje nunca pregunta cómo es el dato sino de quién es su verdad, y clasificar bien exige mirar el origen y el propósito de cada pieza, no su declaración de tipo.
No necesitas un catálogo de casos, solo dos preguntas encadenadas. La primera, de propiedad: poseo esta verdad o solo la leo. Separa el servidor de todo lo demás y suele colocar la mitad del estado de una app sin más discusión. La segunda, de propósito, solo se aplica a lo que el cliente posee: este dato importa al dominio, solo pinta una vista, o describe dónde está el usuario. Dos ejes, cuatro cuadrantes, cero apelaciones al gusto. La parte difícil no es el árbol, es responder con honestidad la primera pregunta sin dejar que el servidor se disfrace de estado propio.
Cada clase, su herramienta
Clasificada la pieza, la herramienta se deduce casi sin margen. Cada clase tiene una naturaleza y una herramienta diseñada para esa naturaleza; forzar una clase en la herramienta de otra es la raíz del desajuste que este track combate desde el Nivel 1.
Servidor: solo lo lees
Perfil, catálogo, pedidos. Su dueño vive en otra máquina y tu copia envejece. Es una cache con política de frescura, no un store. Vive en TanStack Query, SWR o los componentes de servidor.
Cliente: dato de dominio propio
Sesión, carrito local, preferencias, selección que otros módulos consultan. Tu escritura es la verdad y trasciende una sola vista. Vive en Zustand, Jotai o un useState elevado.
UI: apariencia efímera
Desplegable abierto, hover, pestaña interna de un widget, foco. Local a un componente y desechable: si desaparece al recargar, no pasa nada. Vive en useState, o una máquina si el widget tiene modos.
URL: estado navegable
Filtros, página, término de búsqueda, id seleccionado. Compartible por enlace y restaurable al recargar. La URL es un store que el navegador te regala; lo sirve nuqs o el propio router.
La prueba que separa las dos clases más confundidas —cliente de dominio y UI— es doble: durabilidad y alcance. Pregúntate si el dato debería sobrevivir a un recargado y si a alguien fuera de este componente le importa. Si ambas respuestas son no, es UI y se queda local; si alguna es sí, ascendió a dato de cliente y merece un lugar compartido. Un mismo componente lee de las cuatro clases a la vez sin mezclarlas, porque cada dato vive donde su naturaleza manda:
function Panel({ id }: { id: string }) {
const { data: pedidos } = useQuery({ queryKey: ['pedidos', id], queryFn: traer }); // servidor
const tema = useSesion((s) => s.tema); // cliente: dato de dominio propio
const [abierto, setAbierto] = useState(false); // ui: efimero y local
const [filtro] = useSearchParam('filtro'); // url: navegable y compartible
return <Vista pedidos={pedidos} tema={tema} abierto={abierto} filtro={filtro} />;
}
flowchart TD
E[una pieza de estado] --> Q{de quien es la verdad?}
Q -->|vive en otra maquina| S[servidor: es una cache]
Q -->|la posee el cliente| C{para que sirve?}
C -->|dato propio que importa al dominio| K[cliente: store ligero]
C -->|apariencia efimera de una vista| V[ui: useState local]
C -->|describe donde esta el usuario| U[url: navegable y compartible]
style S fill:#f38ba8,color:#11111b
style K fill:#a6e3a1,color:#11111b
style V fill:#89dceb,color:#11111b
style U fill:#fab387,color:#11111bLa frontera y la palanca
De los tres cortes, uno es sagrado: la frontera entre servidor y cliente. Las otras tres clases comparten dueño y se pueden reubicar sin drama —un dato de UI que asciende a cliente, un filtro que se muda a la URL—, pero cruzar la línea servidor-cliente introduce el peor bug del oficio. Copiar un dato de servidor a un store de cliente crea dos verdades del mismo hecho: la remota, que sabe cuándo caduca, y tu copia, que no sabe nada y quedará obsoleta en cuanto la original cambie. Has reconstruido a mano, y peor, la cache que ya tenías gratis.
El error más repetido al montar cualquier arquitectura es traer una lista con la cache y, acto seguido, guardarla en el store para tenerla a mano. En ese instante el dato vive en dos sitios y tú eres responsable de mantenerlos sincronizados: invalidar, revalidar, deduplicar. Nada de eso es trabajo de un store de cliente. La regla no admite excepción cómoda: el dato de servidor vive en la cache y se lee de ella; si otro componente lo necesita, vuelve a leerlo con la misma clave —que deduplica— en vez de copiarlo. Este fue el pecado que hundió a Redux entre 2020 y 2026, y reaparece con cualquier store que le pongas delante.
Por qué esta clasificación es la palanca mayor y no un preámbulo: porque todas las decisiones posteriores dependen de ella y ninguna la puede reparar. Si clasificas primero, elegir librería (Nivel 23) y elegir disciplina de mutación (lección siguiente) se vuelven casi mecánicos, porque operan dentro de una clase ya delimitada. Si no clasificas, ninguna herramienta te salva: el mejor gestor del mundo aplicado a un servidor disfrazado de estado propio sigue produciendo datos obsoletos en pantalla. La palanca está en el orden. Clasificar cuesta minutos y ahorra la reescritura que cuesta meses.
La clasificación se revisa, no se firma
Un malentendido peligroso sería tomar esta clasificación como un acto único que se hace al nacer el proyecto y se da por cerrado. La clase de una pieza depende de hechos que cambian con la app: un dato que hoy usa un solo componente asciende a estado de cliente el día que una segunda pantalla lo lee; un valor que guardabas como propio se descubre derivable de otro y desaparece del estado real; un filtro atrapado en un store se revela navegable y se muda a la URL. La taxonomía es un mapa que se corrige cuando el territorio cambia de forma.
Por eso conviene volver a pasar las dos preguntas cada vez que una pieza cambia de uso, no solo cuando nace. El coste de reclasificar es bajo si diseñaste con fronteras limpias: mover un dato de una clase a otra es cambiar dónde vive, no reescribir la lógica que lo usa. Lo caro no es reclasificar a tiempo, sino descubrir tarde que una pieza llevaba meses en la clase equivocada, sincronizándose a mano y sembrando los bugs que su clase correcta habría hecho imposibles.
Cada vez que introduces una pieza de estado nueva, hazte las dos preguntas en ese instante, antes de decidir dónde la pones. Clasificar en el momento de escribir cuesta segundos y coloca el dato bien desde el principio; clasificar después, cuando ya está mal ubicado y enredado con medio módulo, cuesta un refactor. La disciplina no es una auditoría periódica que haces de vez en cuando: es un reflejo que aplicas en cada declaración de estado, y con la práctica deja de sentirse como un paso extra para volverse la forma natural de pensar el problema.
La tentación perenne de este dominio es creer que existe una herramienta lo bastante buena como para ahorrarte pensar: un gestor de estado que, bien elegido, ordene solo el caos. No existe, y su ausencia no es un defecto del ecosistema sino una verdad sobre la naturaleza del problema. Ninguna librería puede clasificar tu estado porque la clasificación depende de hechos que solo tú conoces: de quién es la verdad de cada dato, si trasciende una vista, si debería sobrevivir a un enlace compartido. Esos hechos son sobre tu dominio, no sobre tu stack, y por eso ningún tipo, ningún framework y ningún patrón los puede inferir. La consecuencia es incómoda y liberadora a la vez. Incómoda porque te devuelve la responsabilidad que esperabas delegar: la arquitectura empieza con un trabajo de análisis que ninguna herramienta hace por ti. Liberadora porque, una vez hecho ese trabajo, casi todo lo demás se deduce, y el interminable debate de librerías se revela como lo que siempre fue —una distracción sobre las hojas de un árbol cuya raíz nunca miraste—. Quien elige herramienta primero fuerza todo el estado a caber en la forma de esa herramienta y paga el desajuste en cada dato que vive donde no le toca: el servidor fingiendo ser propio, la apariencia de un desplegable ocupando un store global, el filtro atrapado en memoria en vez de en la URL. Quien clasifica primero descubre que la mayoría de las decisiones ya estaban tomadas por la naturaleza del dato, y que su libertad real se reduce a un puñado de bifurcaciones honestas. Esta inversión —del catálogo de librerías al análisis del estado— es la destreza que separa a quien colecciona herramientas de quien diseña sistemas, y es, en el fondo, lo único que todo el track quería enseñarte.
- Toma una pantalla de tu app y enumera cada pieza de estado sin decidir aún dónde vive.
- Para cada una, responde la primera pregunta —poseo esta verdad o solo la leo— y aparta de inmediato todo lo que resulte ser cache de servidor.
- A lo que el cliente posee, aplícale la segunda pregunta: dato de dominio, apariencia de UI o ubicación navegable.
- Marca cada divergencia con tu implementación actual: un dato de servidor en el store, un filtro fuera de la URL, apariencia efímera en un store global.
- Localiza un cruce de la frontera servidor-cliente y explica qué bug de sincronización habilita hoy.
- Escribe, en una línea por clase, qué herramienta gobernaría cada cuadrante en una versión limpia de la pantalla.