Duración de la petición TTFB: Reduce el tiempo de procesamiento del servidor

La duración de la solicitud es el tiempo que tu servidor tarda en procesar una solicitud. Es el factor que más contribuye al TTFB en la mayoría de los sitios. Aprende sobre Server-Timing, caché, optimización de bases de datos y correcciones de plataforma.

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2026-03-03

Reduce la subparte de duración de la solicitud del Time to First Byte

Este artículo es parte de nuestra guía sobre el Time to First Byte (TTFB). La duración de la solicitud es la quinta y última subparte del TTFB. Mide el tiempo que tu servidor dedica a procesar realmente una solicitud: recibirla, ejecutar la lógica de la aplicación, consultar bases de datos y generar la respuesta HTML. De todas las subpartes del TTFB, la duración de la solicitud es sobre la que tienes mayor control. Según mi experiencia auditando sitios con CoreDash, es el mayor responsable de un TTFB lento en la mayoría de los sitios web.

El Time to First Byte (TTFB) se puede desglosar en las siguientes subpartes:

¿Buscas optimizar el Time to First Byte? Este artículo se centra en la duración de la solicitud del Time to First Byte. Si no tienes claro qué significa la duración de la solicitud, empieza por qué es el Time to First Byte e identifica y corrige problemas de TTFB primero.

Qué ocurre durante la duración de la solicitud

La duración de la solicitud empieza en el momento en que el servidor recibe la solicitud HTTP y termina cuando envía el primer byte de la respuesta. Todo lo que hace tu servidor en el medio suma a la duración de la solicitud. En un sitio web dinámico típico, esto incluye:

  1. Enrutamiento de la solicitud: el servidor web (Nginx, Apache, IIS) recibe la solicitud y la enruta a la capa de aplicación.
  2. Inicialización de la aplicación: el framework arranca. En WordPress, esto implica cargar el núcleo, los plugins activos y el tema. En Node.js/Express, implica la ejecución del middleware.
  3. Lógica de negocio: tu código de aplicación se ejecuta: controles de autenticación, validación de permisos, transformación de datos, selección de plantillas.
  4. Consultas a la base de datos: la aplicación consulta MySQL, PostgreSQL, MongoDB o el almacén de datos que utilices. Este suele ser el paso más lento.
  5. Generación de la respuesta: la aplicación renderiza la respuesta HTML (o JSON) a partir de plantillas, árboles de componentes o lógica de serialización.

Cada uno de estos pasos añade tiempo. Un servidor bien optimizado completa toda la cadena en menos de 100 ms. Uno mal optimizado puede tardar 800 ms o más, y eso antes de que entren en juego el DNS, la conexión y la latencia de red.

Cómo medir la duración de la solicitud con la API Server-Timing

La cabecera HTTP Server-Timing es la mejor herramienta para diagnosticar la duración de la solicitud. Te permite enviar desgloses de tiempos desde el servidor directamente al navegador, donde aparecen en DevTools y son accesibles mediante la Performance API. Esto significa que puedes medir pasos individuales (consultas a base de datos, renderizado de plantillas, búsquedas en caché) y ver exactamente qué va lento.

El formato de la cabecera Server-Timing es:

Server-Timing: db;dur=53.2;desc="Database queries",
               app;dur=24.1;desc="Application logic",
               tpl;dur=18.7;desc="Template rendering"

Estos valores aparecen en el panel de red de DevTools de Chrome, en la pestaña "Timing", ofreciéndote una cascada del lado del servidor que se asigna directamente a tu código.

Server-Timing en PHP

La función hrtime(true) de PHP proporciona precisión de nanosegundos, haciéndola ideal para medir operaciones individuales en el lado del servidor. Así es como se añade Server-Timing a una aplicación PHP:

// Mide el tiempo de la consulta a la base de datos con precisión de nanosegundos
$dbStart = hrtime(true);
$result = $pdo->query('SELECT * FROM products WHERE active = 1');
$dbDuration = (hrtime(true) - $dbStart) / 1e6; // Convierte a ms

// Mide el renderizado de la plantilla
$tplStart = hrtime(true);
$html = renderTemplate('product-list', ['products' => $result]);
$tplDuration = (hrtime(true) - $tplStart) / 1e6;

// Envía la cabecera Server-Timing al navegador
header(sprintf(
    'Server-Timing: db;dur=%.1f;desc="Database", tpl;dur=%.1f;desc="Template"',
    $dbDuration,
    $tplDuration
));

Server-Timing en Node.js / Express

En Node.js, utiliza process.hrtime.bigint() para cronometraje de alta resolución. Un patrón de middleware te permite medir el tiempo total de procesamiento de la solicitud y las operaciones individuales:

// Middleware de Express para cabeceras Server-Timing
app.use((req, res, next) => {
  const start = process.hrtime.bigint();
  const timings = [];

  // Añade un helper al objeto response
  res.serverTiming = (name, desc) => {
    const mark = process.hrtime.bigint();
    return () => {
      const dur = Number(process.hrtime.bigint() - mark) / 1e6;
      timings.push(`${name};dur=${dur.toFixed(1)};desc="${desc}"`);
    };
  };

  // Antes de enviar la respuesta, añade la cabecera
  const originalEnd = res.end.bind(res);
  res.end = (...args) => {
    const total = Number(process.hrtime.bigint() - start) / 1e6;
    timings.push(`total;dur=${total.toFixed(1)};desc="Total"`);
    res.setHeader('Server-Timing', timings.join(', '));
    originalEnd(...args);
  };

  next();
});

// Uso en un manejador de rutas
app.get('/products', async (req, res) => {
  const endDb = res.serverTiming('db', 'Database');
  const products = await db.query('SELECT * FROM products');
  endDb();

  const endTpl = res.serverTiming('tpl', 'Template');
  const html = renderTemplate('products', { products });
  endTpl();

  res.send(html);
});

Cuellos de botella comunes en la duración de la solicitud

Tras instrumentar cientos de servidores, veo los mismos cuellos de botella una y otra vez. Estas son las causas más comunes de una duración de la solicitud lenta, clasificadas según la frecuencia con la que las encuentro:

  • Consultas lentas a la base de datos: consultas sin indexar, patrones de consulta N+1, escaneos completos en tablas grandes. Esta es la causa número uno. Un solo índice que falte en una tabla de productos de WooCommerce puede añadir de 300 a 500 ms por solicitud.
  • Falta de caché de página: regenerar el mismo HTML para cada visitante cuando el contenido no ha cambiado. Esto es especialmente común en sitios WordPress sin una caché de objetos o un plugin de caché de páginas.
  • Cálculos costosos: ejecutar cálculos complejos, procesamiento de imágenes o agregación de datos en cada solicitud en lugar de almacenar los resultados en caché.
  • Llamadas a API externas: solicitudes síncronas a API de terceros (pasarelas de pago, sistemas CRM, servicios de inventario) que bloquean la respuesta hasta que se completan.
  • Código de aplicación no optimizado: cargar módulos sin usar, ejecutar middleware innecesario o utilizar algoritmos ineficientes para el procesamiento de datos.
  • Arranques en frío: en plataformas serverless (AWS Lambda, Cloudflare Workers, Vercel Functions), la primera solicitud tras un periodo de inactividad sufre una sobrecarga por la inicialización del contenedor.

Soluciones específicas por plataforma

WordPress

Los sitios WordPress son especialmente vulnerables a una duración de la solicitud lenta porque cada carga de página inicializa todo el núcleo de WordPress, todos los plugins activos y el tema. Esto es lo que marca la mayor diferencia:

  • Instala una caché de objetos persistente: Redis o Memcached. WordPress ejecuta docenas de consultas a la base de datos por carga de página, muchas de ellas idénticas entre visitantes. Una caché de objetos (mediante un plugin como Redis Object Cache) almacena estos resultados en memoria, reduciendo el tiempo de la base de datos entre un 60 y un 80 %.
  • Activa la caché de página completa: utiliza una caché de página a nivel de servidor (Nginx FastCGI Cache, Varnish) o un plugin como WP Super Cache. Esto sirve el HTML cacheado directamente sin tocar PHP en absoluto.
  • Audita los plugins lentos: utiliza el plugin Query Monitor para identificar qué plugins generan más consultas a la base de datos o consumen más tiempo de ejecución de PHP.
  • Optimiza las consultas de WooCommerce: WooCommerce es famoso por sus lentas consultas de productos. Activa la función High-Performance Order Storage (HPOS) y añade los índices de base de datos adecuados a la tabla wp_postmeta.

Caso de estudio: Un sitio WordPress redujo la duración de la solicitud de 800 ms a 120 ms implementando caché de objetos (Redis) y optimizando una consulta lenta de productos de WooCommerce que se ejecutaba en cada carga de página. Solo la consulta del producto representaba 450 ms porque realizaba un escaneo completo de tabla en 80.000 filas de postmeta sin un índice.

Node.js

Las aplicaciones Node.js suelen tener una duración de la solicitud rápida por defecto, pero los problemas aparecen a escala o con operaciones bloqueantes:

  • Perfila con el inspector integrado: ejecuta node --inspect app.js y conéctalo a las DevTools de Chrome para identificar funciones pesadas para la CPU. Busca operaciones síncronas que bloqueen el event loop.
  • Activa el registro de consultas del ORM: si usas Sequelize, Prisma o TypeORM, activa el registro de consultas para encontrar patrones N+1 y consultas lentas. En Sequelize: sequelize = new Sequelize({ logging: console.log }).
  • Usa un pool de conexiones: no crees una nueva conexión a la base de datos para cada solicitud. Utiliza un pool de conexiones (integrado en la mayoría de los drivers de base de datos de Node.js) para reutilizar las conexiones.
  • Implementa caché en memoria: para los datos a los que se accede frecuentemente y que no cambian a menudo, usa una caché LRU para evitar consultar la base de datos en cada solicitud.

PHP (sin WordPress)

Para Laravel, Symfony o aplicaciones PHP a medida:

  • Activa OPcache: OPcache de PHP compila los scripts de PHP en bytecode y los almacena en memoria compartida, eliminando la necesidad de analizarlos y compilarlos en cada solicitud. Esto por sí solo puede reducir la duración de la solicitud entre un 30 y un 50 %.
  • Usa precompilación de bytecode: PHP 8.0+ soporta la precompilación (disponible desde PHP 7.4), que carga los archivos del framework en la memoria al arrancar el servidor para no tener que cargarlos por solicitud.
  • Perfila con Xdebug o Blackfire: identifica las funciones específicas que consumen más tiempo de reloj.

Python (Django / Flask)

Las aplicaciones Python a menudo tienen una duración de la solicitud base más alta en comparación con Node.js o PHP:

  • Usa un framework asíncrono: si la espera de E/S es el cuello de botella, considera FastAPI o Django con ASGI para manejar consultas a bases de datos y llamadas a API de manera concurrente.
  • Activa el registro de consultas a la base de datos de Django: configura LOGGING en los ajustes para registrar todas las consultas SQL e identificar las lentas o redundantes.
  • Usa select_related() y prefetch_related(): el ORM de Django generará sin problema consultas N+1 a menos que le indiques explícitamente que una tablas relacionadas.

Pool de conexiones a la base de datos

Abrir una nueva conexión a la base de datos para cada solicitud es una de las causas más comunes, y más evitables, de una duración de la solicitud lenta. Cada conexión nueva requiere un protocolo de enlace TCP (handshake), autenticación e inicialización de la sesión, lo que puede añadir de 5 a 30 ms por solicitud. Bajo carga, esto resulta catastrófico, ya que el servidor de base de datos se queda sin conexiones disponibles.

El uso de un pool de conexiones resuelve esto al mantener un grupo de conexiones abiertas que se reutilizan en las distintas solicitudes. La aplicación toma prestada una conexión del pool, ejecuta sus consultas y devuelve la conexión cuando termina. Esto elimina por completo la sobrecarga de conexión por solicitud.

La mayoría de los drivers de base de datos soportan nativamente los pools de conexiones. En Node.js con pg (PostgreSQL), por ejemplo, se configura así:

const { Pool } = require('pg');

const pool = new Pool({
  host: 'localhost',
  database: 'myapp',
  max: 20,        // Conexiones máximas en el pool
  idleTimeoutMillis: 30000,  // Cierra conexiones inactivas tras 30s
  connectionTimeoutMillis: 2000  // Falla rápido si no hay conexión disponible
});

// Usa pool.query() en lugar de crear nuevos clientes
const result = await pool.query('SELECT * FROM products WHERE id = $1', [id]);

Para aplicaciones PHP detrás de PHP-FPM, considera usar conexiones persistentes (PDO::ATTR_PERSISTENT) o un pooler externo como PgBouncer para PostgreSQL o ProxySQL para MySQL.

Caché de proxy inverso

La respuesta más rápida es la que tu aplicación nunca tiene que generar. Una caché de proxy inverso (Varnish, Nginx FastCGI Cache o una caché edge de CDN) se sitúa delante de tu servidor de aplicaciones y sirve las respuestas cacheadas directamente desde la memoria. Para las páginas que no cambian entre visitantes (lo que incluye la mayoría de las páginas en la mayoría de los sitios web), esto reduce la duración de la solicitud a casi cero.

  • Varnish: una caché HTTP dedicada que puede servir miles de solicitudes por segundo desde la memoria. Configura las cabeceras Cache-Control en las respuestas de tu aplicación y Varnish se encarga del resto.
  • Nginx FastCGI Cache: si ya utilizas Nginx como tu servidor web, activa su caché integrada para las respuestas de PHP-FPM. Esto evita añadir otra capa a tu stack.
  • Caché edge de CDN: servicios como Cloudflare, Fastly y Amazon CloudFront pueden cachear tu HTML en ubicaciones edge por todo el mundo, reduciendo la duración de la solicitud y la latencia de red simultáneamente.

La clave para una caché de proxy inverso eficaz son unas cabeceras Cache-Control correctas. Establece s-maxage para el TTL de la caché compartida y utiliza stale-while-revalidate para servir contenido antiguo mientras la caché se actualiza en segundo plano:

Cache-Control: public, s-maxage=3600, stale-while-revalidate=60

Edge Computing para la duración de la solicitud

Las plataformas de edge computing como Cloudflare Workers y Vercel Edge Functions ejecutan tu código del lado del servidor en las ubicaciones edge del CDN, físicamente cerca de tus usuarios. El edge computing no hará que tu código sea más rápido, pero elimina la latencia de red entre el usuario y tu servidor de origen. Esto es vital para los usuarios alejados de tu centro de datos de origen.

Las edge functions funcionan mejor para:

  • Respuestas ligeras de API que no requieren un acceso intenso a la base de datos
  • Lógica de personalización (pruebas A/B, contenido basado en geolocalización) aplicada en el edge antes de llegar a tu origen
  • Reescritura de HTML y manipulación de cabeceras sin un viaje completo de ida y vuelta al origen

Para las páginas que requieren consultas a la base de datos, el edge computing por sí solo no resolverá los problemas de duración de la solicitud. La verdadera ventaja está en combinar las edge functions con una base de datos distribuida globalmente (PlanetScale, Neon, Turso) o con caché en el edge para mantener todo el ciclo de vida de la solicitud cerca del usuario.

Medir la duración de la solicitud con JavaScript

Puedes medir la subparte de la duración de la solicitud del TTFB directamente en el navegador utilizando la Navigation Timing API:

new PerformanceObserver((entryList) => {
  const [nav] = entryList.getEntriesByType('navigation');

  const requestDuration = nav.responseStart - nav.requestStart;

  console.log('Duración de la solicitud:', requestDuration.toFixed(0), 'ms');
  console.log('  Inicio de la solicitud:', nav.requestStart.toFixed(0), 'ms');
  console.log('  Inicio de la respuesta:', nav.responseStart.toFixed(0), 'ms');

  if (requestDuration > 200) {
    console.warn('Se ha detectado una duración de la solicitud lenta. Comprueba el tiempo de procesamiento del servidor.');
  }
}).observe({
  type: 'navigation',
  buffered: true
});

La duración de la solicitud se calcula como responseStart - requestStart. Un valor consistentemente por encima de 200 ms indica que tu servidor está pasando demasiado tiempo procesando la solicitud. Utiliza la cabecera Server-Timing (descrita anteriormente) para identificar qué parte del procesamiento del servidor es responsable.

Cómo identificar problemas de duración de la solicitud con datos RUM

Para entender cómo la duración de la solicitud afecta a tus usuarios reales, necesitas una herramienta de Real User Monitoring (RUM) como CoreDash. Los datos RUM muestran el desglose del TTFB real que experimentan tus visitantes a través de distintas páginas, dispositivos y ubicaciones. No resultados de laboratorio.

En CoreDash, haz clic en "Time to First Byte breakdown" para visualizar la parte del TTFB correspondiente a la duración de la solicitud. Busca páginas donde la duración de la solicitud supere constantemente los 200 ms. Esos son tus objetivos de optimización.

Lo que muestran nuestros datos

En miles de sitios monitorizados por CoreDash, la duración de la solicitud (tiempo de procesamiento del servidor) es la subparte del TTFB más grande en la mayoría de sitios de nuestro conjunto de datos. Esto convierte a la optimización del servidor en la mayor mejora individual del TTFB para la mayoría de sitios web.

Los sitios con la caché de página completa activada tienen una duración mediana de la solicitud de aproximadamente 35 ms. Los sitios sin ninguna caché tienen una mediana de aproximadamente 320 ms. Esa brecha (casi 10x) es el argumento más sólido que puedo dar para invertir en caché del lado del servidor antes que en cualquier otra cosa.

La duración de la solicitud es parte del Time to First Byte, que es una métrica de diagnóstico para las Core Web Vitals. Para una guía completa sobre cómo identificar y corregir problemas de TTFB, consulta nuestra guía para identificar y corregir el TTFB. También puedes revisar la lista de control definitiva de Core Web Vitals para un resumen exhaustivo de optimización.

Lecturas recomendadas: Guías de optimización

Para técnicas de optimización relacionadas que complementan la optimización de la duración de la solicitud, explora estas guías:

  • 103 Early Hints: envía resource hints (preload, preconnect) al navegador mientras el servidor todavía está procesando la solicitud, reduciendo el TTFB percibido.
  • Configurar Cloudflare para el rendimiento: utiliza caché edge de CDN y configuraciones de servidor optimizadas para reducir la duración de la solicitud de forma global.

Subpartes del TTFB: Guías completas

La duración de la solicitud es una de las cinco subpartes del TTFB. Explora las otras subpartes para entender el panorama completo:

El rendimiento se cae en cuanto dejas de mirar.

Monto el monitoring, los performance budgets y los procesos. Ahí está la diferencia entre un fix y una solución.

Hablemos
Duración de la petición TTFB: Reduce el tiempo de procesamiento del servidor Core Web Vitals Duración de la petición TTFB: Reduce el tiempo de procesamiento del servidor