Esta decisión implica la siguiente pregunta: ¿Cuándo se construye el HTML que ve el usuario?
Hay dos respuestas posibles. La primera, el servidor construye en el momento exacto en que el usuario lo pide, ¿Cómo?, consultando bases de datos y APIs en tiempo real. La segunda respuesta es que la página se construye antes de que nadie la pida, durante el despliegue (build), y se mantiene en espera en una red de servidores (CDN) distribuidos por todo el mundo, lista para servirse al instante. Las dos opciones son totalmente válidas y tienen sentido, pero a su vez, pueden suponer un gran error si se eligen mal.
Una analogía para empezar: dos restaurantes en la misma calle
Imaginemos que en una misma calle se encuentran dos restaurantes donde ambos abren a las nueve de la mañana todos los días. Sirven exactamente la misma comida, pero funcionan de formas radicalmente distintas.
El primer restaurante es un restaurante de cocina al momento. Cuando un cliente entra, pide un plato, el cocinero coge los ingredientes, prepara la receta y lo sirve recién hecho. Cada plato es único, cada cliente puede personalizar como quiera y la calidad es fresca por que está hecho en el momento. Cuando hay poca afluencia, es decir, entran pocos clientes, el cocinero puede ir sacando platos sin ningún problema, pero, ¿qué sucede cuando el cocinero no se encuentra disponible, o entran 40 personas a la vez? Se forma cola. ¿Y si nadie viene? El cocinero sigue estando ahí. ¿Si se pone enfermo? Ese día no se puede abrir.
El segundo es un restaurante de menú del día. Cada mañana el cocinero prepara una cantidad fija de platos: croquetas, lentejas, filete con patatas. Cuando un cliente llega, no espera, el plato está casi listo o listo, el servicio es muy rápido y el cocinero no tiene que estar pendiente del cliente. ¿Problema? No puedes salirte del menú, y si a las tres de la tarde quieres lentejas y ya no quedan, tendrás que esperar a que las preparen de nuevo o conformarte con lo que hay.
En desarrollo web, este es exactamente el dilema. El primer restaurante es lo que se conoce como renderizado dinámico: una forma de generar HTML en el servidor en cada petición o bajo demanda. El segundo es compilación estática: construir antes y servir, conocido como SSG o Static Site Generation.
El coste real de no decidir bien
Antes de adentrarnos en más detalles técnicos conviene darle una vuelta a las cifras. Para una aplicación web de tamaño medio en producción, los datos suelen rondar entre estos baremos:
- Una página servida estáticamente desde un CDN responde en torno a los 50 milisegundos.
- Una página renderizada en servidor en cada petición tarda entre 400 y 800 milisegundos, por que tiene que consultar la base de datos y procesarlo.
- El coste mensual de servir contenido estático es más asequible.
- El coste de mantener servidores activos para renderizar dinámicamente puede subir fácilmente
Hablamos de un x15 en costes y un x16 en velocidad de respuesta. Estos números explican por qué Vercel, Cloudfare o Netlify han construido todo su modelo de negocio alrededor de hacer la opción estática lo más fácil y accesible posible.
Pero, esto no significa que todo deba ser estático, únicamente que todo lo que pueda ser estático, lo sea.
Que pasa exactamente cuando compilas una web
Es importante hacer hincapié en esto porque a menudo la palabra “compilar” se confunde en el mundo web. En el contexto web, compilar significa generar el HTML final antes de que ningún usuario lo pida.
El proceso es el siguiente:
El equipo escribe el contenido, puede ser en un CMS, en archivos markdown, en una base de datos, etc. Cuando se despliega, una herramienta de build, por ejemplo Next.js, Astro, Gatsby, recorre todo el contenido. Por cada página construye el HTML completo: Títulos, textos, imágenes, enlaces, todo lo que se quiere mostrar, estos archivos se suben a un CDN que los esparce por todo el mundo. Después, cuando un usuario en Madrid pide la web, le llega desde el servidor de Madrid, lo mismo sucede cuando un usuario desde Tokio pide la web, se le sirve desde un servidor alojado en Tokio. Todo este proceso no pasa por bases de datos y no se aplica ningún procesamiento intermedio.
Esto implica que el HTML que ve el usuario está físicamente cerca de él. No importa si la base de datos está en Frankfurt por que el HTML está repartido en cien servidores por todo el planeta. Es por esto que una web compilada se siente rápida, instantánea por que el viaje físico de los datos es mucho más corto. Pero es que además tiene otra consecuencia menos obvia: el servidor que generó el HTML ya no existe. Hizo su trabajo durante el deploy y se apagó. No requiere de mantener un servidor encendido las 24 horas del día esperando peticiones, esto radica directamente en que el proceso sea tan barato y a su vez tan seguro.
Qué sucede cuando una web hace peticiones API en tiempo real
El otro extremo del aspecto es totalmente distinto.
Cuando un usuario pide una página, el flujo es el siguiente: la petición llega a un servidor que está activo y esperando, el servidor ejecuta el código de la página, este código consulta la base de datos, llama a APIs externas, procesa la información del usuario (si este está logueado, qué permisos tiene, qué quiere ver). Con toda esta información construye la respuesta del HTML al momento y lo envía al navegador. Cada petición que hace un usuario en la web pasa por todo este ciclo, una y otra vez. Si por ejemplo llegarán mil usuarios de golpe, se repetiría el ciclo mil veces. Si la base de datos va lenta, todas las páginas del sitio web van lentas, si una API externa cae, parte de la web se cae con ella también.
Pero, como con la analogía de los restaurantes, hay una contrapartida que aporta valor, el contenido siempre es fresco y está actualizado y puede ser distinto para cada usuario.
Hay que tener dos cosas en cuenta porque hay dos formas de hacer peticiones API. La primera es la API consumida desde el servidor, es decir, el servidor habla con la API, monta el HTML y se lo entrega al usuario. El usuario nunca ve la API directamente. La segunda es la API consumida desde cliente, el servidor envía una página vacía o con poco contenido y es el navegador del usuario quien hace las llamadas a la API para ir rellenando lo que falta.
Esta diferencia es importante para el SEO ya que los buscadores leen mejor el HTML ya construido que el que es rellenado por Javascript y sobre todo para la seguridad ya que cuando un cliente habla con una API, la URL de esa API es pública.
El espectro completo: SSG, ISR, SSR, CSR y PPR
En realidad no hay solo dos opciones, hay un espectro entero de diferentes estrategias de renderizado, y los frameworks modernos te permiten elegir una distinta para cada parte de la misma aplicación. SSG, SSR, ISR, CSR, y la más reciente PPR (Partial Prerendering), estable desde Next.js 15.
Si quieres entender en detalle cómo funciona cada una, cuándo se usa y qué ventajas e inconvenientes tiene, te lo explicamos en profundidad en este artículo: ¿SSR, CSR, SSG o ISR? Así renderiza la web moderna.
Dado que tenemos todas estas herramientas disponibles, ¿cómo decidimos cuál aplicar a cada pieza de nuestra web? Y especialmente, ¿cuándo tiene sentido compilar y cuándo tiene sentido hacer una llamada a una API?
El buscador de tu web
Pongamos un ejemplo concreto, imaginemos que tenemos un blog corporativo con más de 400 artículos. Queremos que estos artículos se carguen al instante, salgan bien en Google, y no nos cuesten un servidor permanentemente encendido. La respuesta puede ser obvia, compilamos los artículos en build time y los servimos desde un CDN.
Pero tenemos un dilema, ya que queremos que los usuarios puedan buscar directamente dentro del blog. ¿Cómo lo podemos implementar?
Hay tres opciones:
- Opción A: Integrar la búsqueda dentro de la web compilada. Pero esto evoca un problema, deberíamos tener una página por cada búsqueda posible, habría que pre-generar todas las combinaciones de palabras imaginables lo cúal es prácticamente imposible.
- Opción B: Convertir toda la web en dinámica para que el servidor pueda resolver búsquedas en tiempo real. Lo que sucede es que esto afecta a todas las páginas de la web, no únicamente al buscador, cada vista busque o no busque pasa por el servidor. Sacrificamos tiempo, rendimiento y seguridad para dar servicio a una función que quizás utilizará el 5% de los visitantes.
- Opción C: Mantener la web 100% estática y añadir una API independiente que el navegador del usuario llama únicamente cuando la utiliza. Solo es activada cuando alguien la necesita.
Aunque no todas las soluciones encajan exactamente en una de estas tres opciones. Por ejemplo, un buscador que carga todo el contenido del sitio en el navegador al inicio y filtra en local, sin hacer ninguna petición externa. El resultado es un buscador extremadamente rápido que funciona sin servidor y cubre tanto páginas como artículos de un blog. Lo que sucede es que todo este contenido viaja al navegador en la carga inicial, para un sitio con poco volumen de contenido es una decisión razonable, pero para un blog con cientos de artículos puede ser contraproducente ya que estaríamos mandando un volumen de datos innecesario a cada visitante.
Por eso es importante preguntarnos ¿Qué porcentaje de usuarios realmente utiliza la funcionalidad dinámica?
Si el buscador lo utiliza aproximadamente un 5% de nuestros visitantes, no tiene sentido hacer pagar al 95% restante el coste de un sistema dinámico. Pero si en cambio el buscador es la principal forma de navegación, como por ejemplo un comparador de vuelos o un marketplace, entonces sí que merece la pena repensar la arquitectura.
No hay una solución mejor que la otra en abstracto. Hay una solución más adecuada según el volumen de contenido y el perfil de uso. Y la pregunta que hay que hacerse siempre es la misma: ¿cuántos de mis usuarios van a usar realmente esta función?
Seguridad: porque lo estático es más difícil de hackear
La compilación estática tiende a ser más segura por diseño, la razón es física. Cuando una web se sirve desde un CDN como archivos estáticos, no hay un servidor activo procesando peticiones. No hay ninguna base de datos accesible desde fuera, el código no se está ejecutando en producción 24 horas al día.
Si lo comparamos con un Wordpress estándar, un servidor web PHP corriendo 24/7, una base de datos MySQL, un sistema de plugins (la mayoría desactualizados) proporciona una superficie de ataque enorme para alguien malintencionado. En una web estática, todo este rango de ataque no existe. Bueno… El atacante puede intentar tirar el CDN pero la gran mayoría son productos de grandes empresas con grandes medidas de seguridad, lo cual es muy improbable, pero no puede inyectar código ni acceder a una base de datos que no está expuesta.
Esto no significa que las webs estáticas sean invulnerables. Las APIs que consumen sí siguen siendo objetivo. Los formularios que envían datos siguen necesitando validación. Pero la superficie de ataque es radicalmente menor.
¿Cómo se decide en la práctica?
Una vez entendemos más o menos los conceptos, ¿Qué estrategia conviene seguir para qué tipo de página? A continuación expongo una breve guia de como se puede implementar en las diferentes páginas de una web:
- Páginas estáticas: home, “Sobre nosotros”, servicios, casos de éxito, post de blog, documentación, páginas legales adoptando el SSG.
- Páginas con contenido que cambia: catálogo de producto, listado de noticias, listado de eventos. Podemos aplicar ISR con un revalidate razonable, unos 60 segundos para noticias, 1 hora para catálogo, 24 horas para listados que cambian poco.
- Páginas con datos estrictamente personalizados: panel de usuario, historial de compras, configuración de cuenta. Podemos aplicar SSR o CSR según convenga al SEO.
- Funciones puntuales dentro de páginas estáticas: buscador, formulario de contacto, chat de soporte, comentarios. Aplicamos una API en cliente, llama únicamente cuando el usuario la activa.
- Páginas mixtas: una página de producto con precio personalizado, stock en tiempo real y recomendaciones personalizadas. PPR si el stack que utilizamos lo soporta, o SSG con islas dinámicas.
Y la regla de oro que resume todo: compila todo lo que puedas. Consume APIs solo para lo que no puedas compilar. Y llama a esas APIs desde el cliente cuando el SEO no importe, y desde el servidor cuando importe.
El cambio cultural de “todo dinámico” a “estático por defecto”
Hace diez años, la web era abrumadoramente dinámica. WordPress, Drupal, Joomla, sistemas personalizados en PHP o Ruby on Rails. Todos ellos generaban cada página en cada petición con lo cual era costoso y lento, pero era el único modelo que conocíamos. Esta evolución, desde los primeros archivos HTML hasta las arquitecturas JAMstack modernas, es en sí misma una historia fascinante que ya contamos en otro artículo.
El giro empezó con la generación estática moderna, Jekyll primero, Gatsby después y se consolidó con la llegada de Next.js, Astro, Nuxt y los CDNs serverless de última generación. Hoy el patrón ha cambiado: lo dinámico ha pasado de ser el estado por defecto a ser la excepción reservada para lo que de verdad lo necesita.
Conclusión
La decisión entre API y compilación no es un debate técnico abstracto, es una decisión de producto que afecta directamente al negocio. Una web rápida convierte mejor, una web que es barata escala mejor, una web segura cumple mejor con la regulación. Actualmente no hace falta posicionar una por encima de la otra, se pueden tener las tres si diseñamos la arquitectura con criterio.
El error más común es aplicar una única estrategia en toda la aplicación. Hacer que todo sea SSR porque “implementamos un buscador”, hacer que todo sea SSG “por que queremos rendimiento”. La respuesta correcta casi nunca es una sola estrategia, es un mapa de decisiones aplicadas a cada una de las partes de la web.
Y este mapa no se dibuja eligiendo tecnologías, se dibuja entendiendo el contenido, el usuario y el negocio. Cuando tienes clara esta foto, la decisión técnica casi se toma sola.
Referencias
