Elimina la mitad de tu frontend: Dónde HTMX reemplaza tu framework
El servidor es el framework: HTMX para UX web moderna. Cómo decidir cuándo HTMX reemplaza React/Next/Nuxt/SvelteKit, dónde encaja junto a ellos, y cómo construir aplicaciones reales y resilientes con SSE, WebSockets, historia, caché y seguridad.
Si reduces el desarrollo front-end a su esencia, obtienes dos preguntas:
- ¿Cómo cruza la red la intención del usuario?
- ¿Cómo cambia el DOM en respuesta?
Durante una década respondimos ambas con frameworks JavaScript. HTMX las responde con HTML. No es nostalgia—es arquitectura. Al enviar fragmentos HTML sobre HTTP y dejar que los atributos en los elementos describan el comportamiento de red, mueves la lógica de vuelta a donde la web está optimizada: servidores que renderizan documentos y documentos parciales. HTMX luego añade justo la suficiente potencia del cliente (AJAX, SSE, WebSockets, transiciones CSS) a través de atributos hx-* para hacer que las interfaces modernas se sientan instantáneas sin construir un sistema operativo del cliente en tu bundle. La documentación oficial lo dice así: HTMX "te permite acceder a características modernas del navegador directamente en HTML", y es intencionalmente pequeño (≈16.6 KB comprimido en la línea 2.x).
En 2024–2025 HTMX maduró de "hack ingenioso" a opción seria. La versión 2.0 eliminó el soporte para IE, movió los transportes en tiempo real a extensiones de primera clase, y ajustó los valores por defecto; el equipo luego reconsideró abiertamente el snapshotting de historia, abogando por semánticas más simples de request-on-back para evitar el caching local frágil. Estos no son ajustes cosméticos; son movimientos de arquitectura.
Esta guía es para el momento en que miras tu próximo proyecto y preguntas: ¿Debería recurrir a React/Next/Nuxt/SvelteKit—o puedo hacer más con menos usando HTMX?
Definiremos tamaños de proyecto, tomaremos la decisión, y mostraremos patrones, trampas y un ejemplo de producción con SSE y WebSockets.
---
Marco de decisión rápida
Usa HTMX cuando:- Tu "interactividad" es principalmente solicitud/respuesta (enlaces, formularios, actualizaciones parciales)
- Quieres la verdad renderizada en el servidor con una ruta de validación, un caché
- Necesitas tiempo real pero no un OS de cliente (SSE/WebSockets vía atributos)
- Quieres UI direccionable por URL sin un router de cliente
- Offline-first es obligatorio (almacén del cliente, sincronización, resolución de conflictos)
- Tienes una aplicación de cliente verdaderamente con estado, multi-panel (editores nivel Figma, Notion)
- Estás construyendo una plataforma de componentes para compartir entre muchos equipos
---
Qué hace realmente HTMX (y qué no hace)
La idea central: usa atributos HTML para emitir solicitudes HTTP e intercambiar el HTML devuelto en la página actual.
Atributos que usarás todos los días
hx-get,hx-post,hx-put,hx-delete: envía solicitudes e intercambia la respuestahx-swap: controla cómo se inserta el contenido (innerHTML,outerHTML,beforeend,afterbegin, etc.)hx-trigger: decide cuándo se disparan las solicitudes (click,change,every 5s, o eventos personalizados)hx-target: elige qué parte de la página actualizarhx-boost: convierte enlaces y formularios en navegación AJAX con fallback gracefulhx-push-url: actualiza la URL/historia al intercambiar contenido
Tiempo real vía extensiones
- SSE vía
hx-ext="sse",sse-connect="/events", ysse-swap="message"para actualizaciones unidireccionales servidor→cliente sobre HTTP - WebSockets vía
hx-ext="ws",ws-connect="/socket", yws-senden formularios para actualizaciones bidireccionales
Intercambios Out-of-Band
hx-swap-oob permite al servidor actualizar otras partes del DOM incluidas en la misma respuesta (ej., actualizar un contador mientras devuelves un diálogo).
Conciencia del servidor
HTMX envía headers como HX-Request: true, HX-Boosted, HX-Target, y soporta headers de respuesta como HX-Redirect, HX-Location, y HX-Push-Url para que tu servidor pueda devolver fragmentos vs páginas completas y aún controlar la navegación.
Lo que HTMX no hace
Gestión de estado del lado del cliente à la Redux, un DOM virtual, primitivas de composición de componentes, o un router de cliente. Para "código pegamento" en el cliente, usa compañeros mínimos como hyperscript o Alpine.js—ambos funcionan bien con HTMX cuando necesitas estado local o lógica DOM en el navegador.
---
Verificación de realidad 2025: HTMX 2.x y el "fetchening"
A mediados de 2025, HTMX 2.x es la versión actual (2.0.6 notada públicamente). 2.x terminó el soporte de IE, eliminó los viejos hx-sse/hx-ws inline a favor de las extensiones anteriores, e hizo el comportamiento de historia más explícito (y, cada vez más, más simple). Si te quemaste con cachés de snapshot en flujos de atrás/adelante en 1.x/principios de 2.x, los mantenedores ahora te señalan hacia deshabilitar snapshots o dejar que la navegación vuelva a obtener contenido—predecible, más seguro, y más fácil con los servidores de hoy.
---
Decidiendo: Pequeño, Mediano, Grande (sé honesto sobre el alcance)
La mayoría de los equipos sobreestiman el tamaño del proyecto. Usa esto:
Pequeño (1–8 pantallas, acoplamiento bajo)
Tablas CRUD, búsqueda y filtros, formularios, autenticación, un dashboard, un par de modales. Sin requisitos offline. Estado de cliente mínimo entre pantallas.
Por defecto: HTMX + tu templating del servidor. Añade Alpine/hyperscript para estado de UI local. Sin paso de build de framework. Equipo: 1–3 ingenieros, horizonte de entrega de 2–8 semanas.Mediano (8–30 pantallas, acoplamiento moderado)
Suites de admin, back-offices de CMS, sitios de suscripción, dashboards multi-usuario, algo de tiempo real. Offline limitado. Algunos componentes ricos (calendario, gráficos).
Sesgo: HTMX primero. Usahx-boost para navegación, hx-push-url para historia, SSE para actualizaciones en vivo, y añade una micro-lib reactiva (Alpine/hyperscript) donde el estado local sea pesado. Mantén las URLs direccionables y el servidor como fuente de verdad. Añade una pizca de SPA en una sola página solo si es necesario.
Equipo: 3–12 ingenieros, entrega de 2–6 meses en iteraciones.
Grande (30+ pantallas, acoplamiento pesado)
Suites de producto complejas, interacciones de cliente densas, offline, editores embebidos, apps multi-panel con drag-drop y grandes modelos en memoria.
Sesgo: Usa un framework (React/Next, Nuxt/Vue, SvelteKit) para la zona caliente que genuinamente necesita una aplicación de cliente. Usa HTMX en otros lugares—marketing, docs, páginas de cuenta, configuración, UI de facturación. Tu plataforma se vuelve híbrida. El movimiento equivocado no es elegir HTMX; es usar una herramienta a través de formas de problema muy diferentes.---
Cuándo HTMX reemplaza un framework (y cuándo no debería)
Sí reemplaza un framework cuando...
- Tu "interactividad" es principalmente solicitud/respuesta. Enlaces, formularios y actualizaciones parciales dominan. Los atributos HTMX cubren el 90% de lo que escribirías código de cliente.
- Quieres la verdad renderizada en el servidor. Prefieres una validación, una ruta de renderizado, un caché. El
HX-Requestde HTMX permite a tu servidor devolver HTML parcial para fragmentos y páginas completas de lo contrario. - Necesitas tiempo real pero no un OS de cliente. SSE y WebSockets son directos y conducidos por atributos.
- Quieres UI direccionable por URL sin un router de cliente.
hx-boostyhx-push-urlmantienen la historia honesta.
No reemplaza un framework cuando...
- Offline-first es obligatorio. Necesitarás un almacén de cliente, sincronización, resolución de conflictos, orquestación de service worker—fuera del mandato de HTMX.
- Tienes una aplicación de cliente verdaderamente con estado, multi-panel (piensa en editores nivel Figma, Notion). La hidratación y orquestación de estado del cliente son tus problemas principales. Considera React Server Components/Next, Nuxt, o SvelteKit.
- Estás construyendo una plataforma de componentes para compartir entre muchos equipos. Los ecosistemas de framework siguen siendo los más fuertes para esa clase de problema.
El híbrido saludable
HTML-over-the-wire no es único de HTMX—Hotwire/Turbo lo hace en Rails, Symfony, Django y otros. El patrón es estable y mainstream. Muchos productos mezclan: HTMX para la mayoría de las páginas; una sola "isla" de framework para un editor embebido o área intensiva en visualización.
---
Patrones de arquitectura que realmente entregan
1) Navegación progresiva con hx-boost
Envuelve tu contenido principal en hx-boost="true" y deja que los enlaces/formularios se conviertan en solicitudes AJAX que intercambian en . La página aún funciona con JS desactivado.
<main id="app" hx-boost="true" hx-target="#app">
<a href="/invoices">Facturas</a>
<form action="/search" method="get">
<input name="q">
</form>
</main>
Los enlaces boosteados emiten un GET, empujan una entrada de historia, apuntan al body (o tu hx-target elegido), y hacen fallback gracefully.
2) Haz el estado direccionable por URL con hx-push-url
<div id="results"
hx-get="/reports?period=Q2"
hx-push-url="true"
hx-target="#results"
hx-trigger="change from:#period-select">
</div>
hx-push-url actualiza la barra de direcciones e instruye a HTMX a manejar la historia. Los usuarios pueden marcar y compartir estados filtrados.
3) Tiempo real sin una SPA: SSE y WebSockets
SSE para flujos servidor→cliente (tickers de acciones, progreso, notificaciones):<div id="feed" hx-ext="sse" sse-connect="/events" sse-swap="message"></div>
SSE corre sobre HTTP, atraviesa proxies limpiamente, y es unidireccional. La extensión maneja la reconexión y eventos nombrados.
WebSockets cuando el navegador también necesita hablar de vuelta:<div hx-ext="ws" ws-connect="/ws/room">
<div id="chat"></div>
<form ws-send>
<input name="message">
</form>
</div>
Los mensajes entrantes pueden incluir snippets hx-swap-oob para actualizar objetivos en cualquier lugar de la página; la extensión encola mensajes salientes y reconecta con jitter.
4) Actualizaciones Out-of-Band para "mientras estás aquí..."
Devuelve el fragmento principal y una actualización de insignia en una respuesta:
<div id="modal">...</div>
<div id="alerts" hx-swap-oob="true">¡Guardado!</div>
La respuesta del servidor actualiza tanto el modal como la región de alertas.
5) Comportamiento del cliente: usa hyperscript/Alpine con moderación
- hyperscript favorece comportamientos pequeños y legibles inline:
_="on click toggle .open on #menu" - Alpine.js trae estado pequeño y reactivo cuando lo necesitas (dropdowns, tabs), y hay una extensión
alpine-morphpara preservar el estado de Alpine a través de swaps
---
Rendimiento, payload y velocidad percibida
- Tamaño del bundle: HTMX 2.x es ≈16–17 KB comprimido (más cualquier extensión que uses). Para muchas apps eso reemplaza 100–300 KB de framework + router + gestión de estado + código de hidratación.
- Arranques en frío: Sin boot/hidratación de framework, el tiempo interactivo es a menudo "HTML parseado" + "un pequeño eval de script".
- Red: Estás enviando fragmentos HTML, no JSON + templates de cliente. Eso ahorra duplicación (no "renderizar en servidor luego renderizar de nuevo en cliente") y permite a los CDNs cachear fragmentos agresivamente.
---
Historia, caché y la guía de 2025
HTMX históricamente hacía snapshot del DOM para navegar hacia atrás instantáneamente. En la práctica, scripts de terceros y peculiaridades del navegador hacen los snapshots frágiles. Los mantenedores ahora recomiendan deshabilitar el snapshotting por URL con hx-history="false" (o globalmente) y dejar que el navegador vuelva a obtener contenido en atrás/adelante. Aún obtienes historia correcta, pero menos heisenbugs y menor superficie de ataque de estado del cliente.
---
Seguridad: XSS, CSRF y corrección de fragmentos
- XSS: Estás renderizando HTML desde el servidor; escapa datos no confiables en el límite del template y mantén el auto-escape de tu motor de templating activado. La guía de XSS de OWASP aplica 1:1 aquí.
- CSRF: Incluye tokens CSRF en POST/PUT/PATCH/DELETE. Con Django, por ejemplo, usa
csrf_tokenen formularios o añade el token víahx-headers. - Descargas de archivos: Porque HTMX usa XHR/fetch, generalmente rediriges el navegador (
HX-Redirect) a un endpoint no-AJAX para descargas reales.
---
Comparación con frameworks modernos (edición 2025)
- React / Next.js: Server Components eliminan código de data-fetch del cliente y reducen hidratación, pero aún mantienes un grafo de componentes, límites y bundling; adoptas convenciones para streaming y capas de caché; y eliges componente de cliente vs servidor cuidadosamente. Esto es poderoso, pero pesado si tu UI es principalmente hypermedia clásica.
- Nuxt (Vue) y SvelteKit: Ofrecen historias SSR/ISR/híbridas igualmente excelentes y son geniales cuando necesitas estado de cliente rico y grandes bibliotecas de componentes.
- Hotwire/Turbo: El primo más cercano—un conjunto de herramientas nativas de Rails (Drive/Frames/Streams) para HTML-over-the-wire con buenas primitivas de tiempo real y una "sensación de SPA sin el bloat de SPA". HTMX te da la misma idea en un estilo agnóstico de framework, primero atributos.
---
Un ejemplo del mundo real: Pedidos en vivo (SSE + WebSockets), cero framework
Escenario
Estás construyendo una consola de "Pedidos en vivo" pequeña–mediana para una cadena de cafeterías. Requisitos:
- Lista de pedidos paginada con filtros y estado compartible por URL
- Inyección de fila "nuevo pedido" en tiempo real
- Botón para aceptar un pedido y ver el contador de insignias bajar
- Cambios de estado transmitidos (el display de cocina actualiza a todos)
1) Layout y navegación boosteada
<body>
<header>
<a href="/orders" hx-boost="true">Pedidos</a>
<a href="/reports" hx-boost="true">Reportes</a>
<span id="badge" class="badge">0</span>
</header>
<main id="app" hx-boost="true" hx-target="#app">
{{ template "orders/index.html" . }}
</main>
<script src="/static/htmx.min.js"></script>
<script src="/static/sse.js"></script>
<script src="/static/ws.js"></script>
</body>
2) Filtro + estado de URL
<form id="filters"
hx-get="/orders"
hx-target="#orders"
hx-push-url="true"
hx-trigger="change delay:300ms from:#status,#search">
<select id="status" name="status">
<option value="">Todos</option>
<option>NUEVO</option><option>PREP</option><option>LISTO</option>
</select>
<input id="search" name="q" placeholder="Buscar...">
</form>
<div id="orders">
{{ template "orders/table.html" . }}
</div>
3) Actualizaciones en tiempo real (SSE)
<div id="realtime"
hx-ext="sse"
sse-connect="/events/orders"
sse-swap="message"></div>
4) Aceptar pedido (viaje redondo de WebSocket)
<div hx-ext="ws" ws-connect="/ws/orders">
<table id="orders-table">...</table>
<form ws-send onsubmit="return false">
<input type="hidden" name="action" value="accept">
<input type="hidden" name="order_id" value="{{ .ID }}">
<button>Aceptar</button>
</form>
</div>
5) Lista de verificación QA para producción
- Manejo de 404/401/422: Mapea códigos de respuesta a swaps o mensajes
- CSRF: Añade token vía input oculto o
hx-headers - Control de acceso: Los endpoints SSE y WS deben enforcar auth y scoping de tenant por conexión
- Backpressure: Throttle de flujos SSE/WS por usuario
- Caché: Cachea fragmentos HTML en el edge; purga en actualización
- A11y: Asegura que las regiones intercambiadas estén en regiones live (
role="status"/aria-live="polite") - Descargas de archivos: Usa
HX-Redirectpara disparar una descarga completa del navegador
---
Dónde brilla HTMX (resumen)
- Verdad renderizada en servidor: Sin duplicar validación/lógica de vista del cliente
- Velocidad: Runtime pequeño, sin impuesto de hidratación, tiempo real multi-transporte
- Mejora progresiva por defecto: Enlaces/formularios boosteados funcionan incluso con JS desactivado
- URL + historia en la que puedes confiar: Push state cuando importa, refetch en lugar de snapshot cuando es más seguro
- Componible con herramientas pequeñas: hyperscript/Alpine para estado local donde se necesite
Dónde HTMX es la herramienta equivocada
- Offline-first o estado de cliente pesado
- UIs de editor complejas que son esencialmente apps de escritorio en el navegador
- Grandes marketplaces de componentes donde necesitas SSR + CSR + hidratación + una gramática de componentes compartida—los frameworks aún ganan
---
Playbook de migración (React/Next/Nuxt → HTMX, cuidadosamente)
- Elige una página (ej., "Pedidos"). Renderízala del lado del servidor con tus templates existentes.
- Envuelve main en hx-boost, y asegura que cada enlace/formulario adentro navegue e intercambie en el objetivo principal.
- Reemplaza un componente a la vez con un parcial del servidor +
hx-get/hx-post. - Conecta la historia con
hx-push-urlpara filtros marcables. - Añade SSE para actualizaciones pasivas; usa WS solo si el cliente debe hablar de vuelta.
- Mantén una isla de framework donde sea verdaderamente necesario (editor rico, whiteboard). No fuerces la pureza.
---
La vista estratégica
La última década construyó motores de cliente para hacer que la web se sintiera como apps. La próxima década hará el compute fungible de nuevo: fragmentos HTML renderizados cerca de los datos, transmitidos a un cliente delgado y robusto que también puede hacer suficiente lógica local cuando sea necesario. React/Next/Nuxt/SvelteKit son ideales para problemas verdaderamente con forma de app. Pero mucho de tu producto sigue siendo documentos que cambian—formularios, tablas, listas, detalles, diálogos. HTMX mantiene esos honestos y rápidos.
Si estás empezando un proyecto pequeño o mediano en 2025, empieza con HTMX y añade una pizca de Alpine o hyperscript. Si estás construyendo una app grande, haz de HTMX el default para cada página que no demande una aplicación de cliente; reserva el framework para las partes que sí lo hacen.
Entregarás más rápido, debuggearás menos, y pasarás tu tiempo donde importa: el servidor que conoce tus datos.
---
Sobre el autor: Odd-Arild Meling ha construido aplicaciones web durante tres décadas, desde PHP renderizado en servidor temprano hasta la era completa de React/SPA y de vuelta a arquitecturas HTML-primero. En Gothar usamos HTMX con Hono en Cloudflare Workers—fragmentos renderizados en servidor en el edge, TTFB sub-50ms, cero overhead de framework. Porque la mayoría de la web sigue siendo documentos que cambian, y el servidor sigue conociendo mejor tus datos.