Rendimiento · Laravel
Cómo detectar y corregir el problema N+1 en Laravel
Publicado el 26 de setiembre de 2026 · 6 min de lectura
Si tu sistema Laravel se pone lento a medida que crecen los datos —listas que tardan segundos en cargar, reportes que se cuelgan, endpoints de API que responden cada vez peor— hay una probabilidad alta de que el culpable sea el clásico problema N+1. Es una de las causas de lentitud más comunes que encontramos al hacer diagnósticos técnicos, y también una de las más fáciles de corregir una vez identificada.
¿Qué es el problema N+1?
Ocurre cuando tu código ejecuta una consulta para traer una lista de N registros, y luego ejecuta una consulta adicional por cada uno de esos registros para traer una relación. En vez de 2 consultas, terminas ejecutando N+1: una para la lista, y N más para las relaciones.
// ❌ Esto dispara 1 consulta por cada pedido (N+1)
$pedidos = Pedido::all();
foreach ($pedidos as $pedido) {
echo $pedido->cliente->nombre; // consulta adicional en cada vuelta
}Con 20 pedidos en la lista, esto son 21 consultas a la base de datos en vez de 2. Con 2,000 pedidos, son 2,001. El sistema "funciona" en desarrollo con pocos datos, pero se vuelve inutilizable en producción con datos reales — por eso muchas veces pasa desapercibido hasta que el negocio ya creció.
Cómo detectarlo
No necesitas adivinar. Estas son las formas más confiables de encontrarlo:
- Laravel Debugbar (
barryvdh/laravel-debugbar): muestra cuántas consultas SQL se ejecutaron por página. Si ves 50+ consultas casi idénticas variando solo el ID, es N+1. - Laravel Telescope: además de contar consultas, te deja ver el stack trace exacto de dónde salió cada una, muy útil en sistemas grandes.
- beyondcode/laravel-query-detector: paquete pensado específicamente para esto — lanza una advertencia en pantalla apenas detecta el patrón N+1 durante desarrollo.
- Monitoreo en producción (Sentry, New Relic, CloudWatch): si no puedes reproducirlo en local, revisar cuántas queries dispara un endpoint lento en producción también lo delata.
Cómo corregirlo: Eager Loading
La solución casi siempre es la misma: en vez de dejar que Eloquent cargue la relación "perezosamente" en cada vuelta del bucle, le pides que la cargue de una sola vez, junto con la lista principal, usando with():
// ✅ 2 consultas en total, sin importar cuántos pedidos haya
$pedidos = Pedido::with('cliente')->get();
foreach ($pedidos as $pedido) {
echo $pedido->cliente->nombre; // ya está cargado en memoria
}Algunas variantes que también vale la pena conocer:
with('cliente.empresa')— eager loading anidado, para relaciones de relaciones.loadMissing('cliente')— carga la relación solo si aún no fue cargada (útil cuando el mismo código se reutiliza en distintos contextos).withCount('pedidos')— si solo necesitas un conteo, no cargues toda la relación.select()— combina eager loading con selección explícita de columnas para no traer datos que no vas a usar.
Como buena práctica, en sistemas donde el problema tiende a reaparecer (equipos grandes, mucho código legado), puedes activar Model::preventLazyLoading() en el entorno de desarrollo para que Laravel lance una excepción cada vez que algo intente hacer lazy loading — así el problema se detecta en el momento en que se escribe el código, no meses después en producción.
En resumen
El N+1 casi nunca se nota con pocos datos de prueba, y por eso suele llegar a producción sin que nadie lo note — hasta que el negocio crece y el sistema empieza a sentirse lento sin una causa obvia. Detectarlo con las herramientas correctas y corregirlo con eager loading suele ser uno de los cambios con mayor impacto en rendimiento por menor esfuerzo que existen en una aplicación Laravel.
¿Tu sistema tiene este problema y no sabes dónde?
En nuestro servicio de mantenimiento y optimización Laravel revisamos tu sistema con estas mismas herramientas y te entregamos un informe con los problemas encontrados y su impacto real.
Solicitar diagnóstico técnico