Eager Loading vs Lazy Loading en Laravel Nova
Comparación práctica de eager vs lazy loading en Laravel Nova: cuándo usar cada uno, evitar N+1 y optimizar consultas con $with, collapsable y autoloading.
Cuando trabajas con Laravel Nova, elegir entre eager loading y lazy loading afecta directamente el rendimiento de tus dashboards. Aquí está la clave:
- Lazy Loading: Carga relaciones solo cuando se accede a ellas. Es útil para datos condicionales, pero puede generar el problema N+1, ralentizando vistas con muchos registros.
- Eager Loading: Carga relaciones por adelantado con
with(), reduciendo consultas y mejorando tiempos en vistas con múltiples recursos. Es ideal para listas de registros en Nova.
Comparación rápida:
| Aspecto | Lazy Loading | Eager Loading |
|---|---|---|
| Consultas SQL | 1 + N (por cada relación) | 1 o 2 (independiente del tamaño) |
| Uso inicial de memoria | Bajo | Alto |
| Velocidad inicial | Más rápida | Más lenta |
| Escenario ideal | Relaciones condicionales | Listas de recursos |
Conclusión: Usa eager loading en vistas con muchos registros y lazy loading en datos condicionales. Combina ambas técnicas según el contexto para optimizar rendimiento.
Eager Loading vs Lazy Loading en Laravel Nova: Comparación de Rendimiento
NEW in Laravel 12.8: Automatic Eager Loading to Avoid N+1 Query

¿Qué es el Eager Loading en Laravel Nova?

El eager loading (o carga anticipada) es una técnica que permite precargar datos relacionados en una o pocas consultas, evitando el problema conocido como N+1. En lugar de ejecutar una consulta independiente cada vez que se accede a una relación, Eloquent realiza dos consultas: una para obtener los datos principales y otra para las relaciones, utilizando una cláusula WHERE IN.
Por ejemplo, si necesitas mostrar 100 publicaciones junto con sus comentarios, sin usar eager loading, se generarían 101 consultas (una para cada publicación y sus comentarios). Con eager loading, ese número se reduce a solo 2 consultas. Esto mejora considerablemente el rendimiento, especialmente en las vistas de índice y detalle de Nova, donde se manejan múltiples registros y relaciones.
Cómo Implementar el Eager Loading
Para implementar esta técnica en Laravel Nova, la forma más sencilla es mediante la propiedad $with en la clase Resource. Esta propiedad recibe un array con los nombres de las relaciones que deseas precargar:
public static $with = ['author', 'category'];
If you routinely need to access a resource's relationships within your fields, resource title, or resource subtitle, it may be a good idea to add the relationship to the
withproperty of your resource.
Esto resulta especialmente útil si el título o subtítulo de un recurso depende de una relación, como mostrar el nombre del autor en el título de una publicación.
Además, puedes optimizar el uso de memoria limitando las columnas que se cargan, por ejemplo: Post::with('category:id,title'). También es posible cargar relaciones anidadas utilizando la notación de punto: with('posts.comments.author').
Opciones de Configuración Global
Laravel Nova también permite configurar el eager loading a nivel global. Desde Laravel 12.8, se introdujo la funcionalidad de "Automatic Relationship Loading", que detecta dinámicamente las relaciones accedidas y las carga automáticamente en lotes, sin necesidad de usar manualmente with() o load().
Automatic eager loading in Laravel 12.8 is a subtle but powerful upgrade that lets you write cleaner, more maintainable code while sidestepping one of the most common performance pitfalls.
Para habilitar esta funcionalidad globalmente, agrega lo siguiente al método boot de tu AppServiceProvider:
Model::automaticallyEagerLoadRelationships();
Si solo quieres activarlo en modelos específicos, utiliza: protected $autoLoadRelations = true;. Esta característica puede reducir entre un 60 % y un 80 % las consultas en aplicaciones con relaciones complejas y profundamente anidadas.
Durante el desarrollo, es recomendable habilitar Model::preventLazyLoading(!app()->isProduction()); en el AppServiceProvider. Esto lanzará una excepción si se detecta lazy loading, ayudándote a identificar y resolver problemas N+1.
¿Qué es el Lazy Loading en Laravel Nova?
El lazy loading (o carga diferida) es el comportamiento predeterminado en Eloquent y Laravel Nova. Básicamente, este método carga datos relacionados solo cuando se accede a ellos. Inicialmente, solo se recuperan los datos del modelo principal, y las relaciones se consultan más tarde, si es necesario. Esto hace que las consultas iniciales sean rápidas, pero puede traer problemas de rendimiento en las vistas de índice de Nova, donde se muestran múltiples registros al mismo tiempo. Por ejemplo, si un recurso necesita datos de una relación para mostrar un campo, como el nombre de un autor en una relación BelongsTo, se ejecutará una consulta SQL separada por cada registro mostrado.
"The convenience of lazy-loading is nice, but it can come with heavy performance burdens in the long-term." - Paul Redmond, Staff Writer, Laravel News
Cómo Funciona el Lazy Loading en Nova
Cuando Nova carga un recurso, solo recupera los datos del modelo principal en la consulta inicial. Si después se accede a una relación, Laravel ejecuta una nueva consulta en ese momento. Esto es útil para registros individuales o cuando las relaciones se acceden de manera condicional, ya que solo se carga lo necesario.
El problema surge en paneles con grandes volúmenes de datos. Aunque la carga inicial puede parecer rápida, el rendimiento se deteriora cuando las vistas o campos necesitan acceder a relaciones adicionales. En proyectos con millones de registros, este enfoque puede causar errores 504 o páginas que no responden, especialmente si campos como BelongsTo intentan cargar listas completas de datos.
Para mitigar esto, Nova retrasa la carga de ciertas relaciones hasta que el usuario expande su sección, lo que mejora los tiempos iniciales de carga. Sin embargo, este comportamiento contrasta con el enfoque de carga anticipada, que se discutirá más adelante.
El Problema de las Consultas N+1
El problema N+1 ocurre cuando la aplicación realiza una consulta para obtener una colección de registros y luego ejecuta consultas adicionales para recuperar los datos relacionados de cada uno.
"The N+1 problem is sneaky - your code might look perfect, but your server is doing extra work in the background." - yohan dhanushka fernando
Por ejemplo, en un proyecto real de dashboard, el lazy loading generó más de 15 consultas para una sola página paginada, afectando gravemente el rendimiento. Implementar eager loading en lugar de lazy loading puede marcar una gran diferencia. Para una colección de 100 pedidos, el tiempo de ejecución total puede reducirse de 500 ms a 150 ms. Además, mientras que el lazy loading escala linealmente con el número de registros (más registros, más consultas), el eager loading mantiene el número de consultas constante, generalmente solo dos, sin importar si se manejan 5 o 5.000 registros.
Entender estas diferencias es clave para optimizar los dashboards en Laravel Nova y evitar cuellos de botella en proyectos con grandes cantidades de datos.
Eager Loading vs Lazy Loading: Comparación Directa
Cuando se trata de manejar relaciones en bases de datos, eager loading y lazy loading ofrecen enfoques distintos, cada uno con sus propias ventajas y desafíos.
Lazy loading genera 1 + N consultas (una por cada relación), mientras que eager loading se limita a 1 o 2 consultas. Esto significa que lazy loading puede parecer más ágil al inicio, ya que solo carga los datos principales, pero eager loading, aunque tiene una sobrecarga inicial, mantiene tiempos de respuesta más consistentes al manejar grandes volúmenes de registros.
En términos de memoria, la diferencia también es significativa. Por ejemplo, cargar 1.000 productos con todas sus reseñas e imágenes mediante eager loading puede consumir hasta 100 MB, mientras que con lazy loading, si no se cargan las relaciones, el consumo inicial es de solo 10 MB. Sin embargo, lazy loading puede provocar picos de uso de memoria al acceder repetidamente a las relaciones, lo que puede afectar la experiencia del usuario, especialmente en paneles de administración donde la fluidez es clave.
Tabla de Comparación Lado a Lado
| Característica | Lazy Loading | Eager Loading |
|---|---|---|
| Consultas SQL | 1 + N (alta) | 1 o 2 (baja) |
| Rendimiento Inicial | Rápido | Más lento (sobrecarga inicial) |
| Consumo de Memoria | Bajo inicialmente, crece con el tiempo | Alto (carga todo de una vez) |
| Protección N+1 | No | Sí |
| Caso de Uso en Nova | Páginas de detalle (campos colapsables) | Vistas de índice (listas de recursos) |
| Escenario Recomendado | Cuando los datos se acceden condicionalmente | Cuando los datos siempre se muestran |
Ventajas y Desventajas
Eager loading es especialmente útil en vistas de índice, como las listas de recursos en Nova, donde se requiere mostrar datos relacionados para múltiples registros. Este enfoque puede reducir el tiempo de ejecución total de 500 ms a 150 ms al procesar 100 pedidos. Sin embargo, su principal inconveniente es el alto consumo de memoria, especialmente al cargar relaciones complejas. Para mitigar este problema, es recomendable limitar las columnas seleccionadas utilizando métodos como with('category:id,title').
"Eager loading is preferred when you know you'll need the related data for multiple records." - Muhammad Haseeb, PHP Laravel Developer
Por otro lado, lazy loading es ideal para páginas de detalle donde las relaciones solo se acceden bajo ciertas condiciones. En Nova, se puede usar collapsable() para cargar los datos únicamente cuando el usuario expande la sección correspondiente. A pesar de esta flexibilidad, lazy loading puede ser problemático debido al famoso problema N+1. Por ejemplo, en un dashboard estándar de publicaciones, este enfoque puede generar más de 15 consultas para una sola página paginada con 10 elementos. Para evitar estos problemas, es útil activar Model::preventLazyLoading(!app()->isProduction()) en entornos de desarrollo, lo que permite identificar y corregir estas ineficiencias antes de llegar a producción.
Cuándo Usar Eager Loading en Laravel Nova
Mejores Escenarios para Eager Loading
El eager loading resulta esencial cuando trabajas con vistas índice que muestran múltiples recursos simultáneamente. Por ejemplo, en una lista estándar de 25 registros con una relación BelongsTo, el lazy loading genera 26 consultas a la base de datos, mientras que con eager loading esas consultas se reducen a solo 2 . Esta diferencia es especialmente importante en dashboards complejos que manejan datos de varios modelos .
Otro caso clave son las relaciones polimórficas (MorphTo). Sin eager loading, cada registro puede disparar múltiples consultas adicionales para identificar el tipo de modelo relacionado, lo que puede saturar la base de datos . Además, es muy útil en relaciones anidadas de varios niveles, como Tutorial -> Sections -> Classes. Aquí, la notación de punto with('sections.classes') permite consolidar la recuperación de datos en una sola operación eficiente .
"Eager loading can improve the performance of your application by reducing the number of database queries needed to fetch related models." - Samson Omojola, Software Developer, Honeybadger
Los recursos diseñados para alimentar APIs o herramientas internas que requieren estructuras completas de datos también se benefician enormemente. En aplicaciones prácticas, implementar eager loading ha permitido reducir el total de consultas en una sola página de 68 a 20, mejorando notablemente los tiempos de respuesta. Aunque esta técnica es poderosa, un uso excesivo puede ser contraproducente. A continuación, veremos cómo evitarlo.
Evitar el Eager Loading Excesivo
Cargar relaciones o columnas innecesarias puede afectar gravemente el rendimiento. Por ejemplo, recuperar 10 MB de datos sin limitar las columnas puede hacer que un dashboard sea inutilizable. La solución es restringir las columnas mediante la sintaxis with('relation:id,name'), lo que permite cargar solo los campos esenciales para la visualización en Nova, optimizando el uso de memoria .
En el caso de relaciones polimórficas, puedes usar morphWith para especificar qué columnas cargar según el tipo de modelo, evitando incluir campos "pesados" innecesarios. Además, si solo necesitas mostrar el número de elementos relacionados (por ejemplo, "Total Comentarios"), es más eficiente usar withCount('comments') en lugar de cargar toda la relación. Este enfoque minimiza el consumo de memoria y asegura un rendimiento óptimo sin comprometer la funcionalidad del dashboard.
Cuándo Usar Lazy Loading en Laravel Nova
Mejores Escenarios para Lazy Loading
El lazy loading es ideal para relaciones condicionales u opcionales que no siempre se necesitan mostrar. En interfaces de administración, donde los usuarios pueden acceder a diferentes niveles de datos según sus acciones, cargar todas las relaciones desde el principio puede desperdiciar recursos innecesariamente. Por ejemplo, el eager loading podría recuperar datos como publicaciones, comentarios o "me gusta" que, al final, ni siquiera se mostrarán.
En Laravel Nova, el método collapsable() implementa lazy loading. Esto significa que los datos de una relación no se consultan en la base de datos hasta que el usuario expande ese panel en la interfaz. Esto es especialmente útil para relaciones que incluyen campos pesados, como textos extensos o datos binarios.
"Lazy loading is more appropriate when the related data might not be needed immediately or is needed conditionally." - Muhammad Haseeb, PHP Laravel Developer
Otro caso importante es el uso de searchable() en campos de relación. Si tienes un menú desplegable con más de 10.000 registros, este método optimiza las consultas al solicitar solo los datos necesarios bajo demanda, evitando problemas de memoria. Además, durante las primeras etapas de desarrollo, cuando aún no se tienen claros los patrones de acceso a los datos, el lazy loading ofrece la flexibilidad necesaria sin afectar el rendimiento.
Esta estrategia permite combinar diferentes enfoques para ajustar el rendimiento según las necesidades.
Mezclar Lazy y Eager Loading
La combinación de lazy loading y eager loading puede ser clave para equilibrar el rendimiento y el uso de memoria dependiendo del contexto. Métodos como load() o loadMissing() permiten cargar relaciones después de haber obtenido el modelo principal, resolviendo problemas N+1 cuando se requieren relaciones de forma inesperada. En particular, loadMissing() ejecuta la consulta solo si la relación no ha sido cargada previamente, evitando así consultas innecesarias.
En Laravel 12.8, se introduce withRelationshipAutoloading(), una funcionalidad que detecta cuándo se accede a una relación y la carga de manera eficiente, sin necesidad de declarar explícitamente with(). Este método actúa como un punto intermedio, manteniendo un bajo consumo de memoria inicial y resolviendo el problema N+1 al cargar en bloque las relaciones cuando se acceden por primera vez.
Para evitar lazy loading no intencionado, puedes activar Model::preventLazyLoading(!app()->isProduction()) en el archivo AppServiceProvider. Esto te permitirá identificar y ajustar las relaciones que deberían cargarse con eager loading. Además, herramientas como Laravel Debugbar o DB::listen son útiles para auditar cuántas consultas genera el lazy loading en los dashboards de Nova, ayudándote a optimizar la estrategia según las necesidades específicas de cada vista.
Consejos de Optimización de Rendimiento para Laravel Nova
Monitoreo y Análisis de Consultas
Para mejorar el rendimiento, es esencial analizar cuántas consultas SQL se ejecutan en cada petición. Herramientas como Laravel Debugbar o el método DB::listen son ideales para visualizar tanto el número de consultas como su duración. Por ejemplo, en un caso documentado, una vista de paginación estándar con 10 elementos generó más de 15 consultas debido a comprobaciones de sesión, permisos y relaciones.
Habilitar Model::preventLazyLoading(!app()->isProduction()) en el AppServiceProvider ayuda a detectar problemas de lazy loading y a prevenir errores N+1 antes de que lleguen a producción. Además, este monitoreo puede identificar problemas de sobre-recuperación (over-fetching). Para evitar esto, especifica las columnas necesarias utilizando $with, lo que puede reducir el uso de memoria en un 50% cuando trabajas con grandes volúmenes de datos.
Este análisis permite optimizar el uso de eager o lazy loading, según lo requiera cada caso, y abordar ineficiencias relacionadas con las nuevas características de autoloading.
Uso de las Funcionalidades de Autocarga de Laravel 12.8
Laravel 12.8 introduce mejoras significativas en la carga automática de relaciones, complementando las estrategias de monitoreo. Automatic Relation Loading detecta automáticamente qué relaciones se acceden y las carga en lotes eficientes, eliminando la necesidad de declarar manualmente with() o load(). En un caso de prueba, al trabajar con usuarios y sus relaciones (distrito, estado y país), esta funcionalidad redujo las consultas de 302 a solo 5.
"Automatic eager loading in Laravel 12.8 is a subtle but powerful upgrade that lets you write cleaner, more maintainable code while sidestepping one of the most common performance pitfalls." - Laravel 12
Puedes implementar esta funcionalidad en tres niveles: de forma global en el AppServiceProvider con Model::automaticallyEagerLoadRelationships(), en modelos específicos usando protected $autoLoadRelations = true;, o en colecciones mediante withRelationshipAutoloading(). Esto resulta especialmente útil en Laravel Nova para vistas de detalle que muestran varias relaciones anidadas, como $order->client->owner->company->name. El sistema emplea automáticamente loadMissing() para reducir el consumo inicial de memoria y resolver problemas N+1 de manera eficiente.
Conclusión
En Laravel Nova, elegir entre lazy loading y eager loading dependerá de las necesidades específicas de cada caso. Como explica Andrés Cruz: "ninguna técnica es mejor que la otra, ambas se utilizan para optimizar el rendimiento de la aplicación reduciendo el número de consultas a la base de datos necesarias para obtener datos relacionados".
El lazy loading es excelente para mantener las consultas iniciales ligeras y consumir menos memoria, lo que lo hace ideal para relaciones condicionales. Sin embargo, en vistas de índice, puede provocar el temido problema N+1. Por otro lado, el eager loading, utilizando la propiedad $with, reduce drásticamente el número de consultas, aunque puede aumentar el consumo de memoria si no se limitan las columnas. En paneles con grandes volúmenes de datos, la clave está en combinar ambas estrategias: emplea eager loading para relaciones que se muestran en títulos o subtítulos y utiliza collapsable() para cargar relaciones más pesadas bajo demanda en las páginas de detalle.
Con las mejoras introducidas en Laravel 12.8, estas técnicas se potencian aún más. La carga automática de relaciones optimiza dinámicamente las consultas, adaptándose al contexto. Además, herramientas como Laravel Debugbar y la función preventLazyLoading() ofrecen un monitoreo detallado, haciendo posible la creación de dashboards rápidos y eficientes que se ajustan a las necesidades específicas de cada proyecto.
FAQs
¿Cómo impacta el lazy loading en el rendimiento de los paneles de Laravel Nova?
Cuando se utiliza lazy loading en los paneles de Laravel Nova, puede afectar seriamente al rendimiento. Esto ocurre porque cada relación genera una consulta independiente a la base de datos al renderizar filas o tarjetas. Este fenómeno, conocido como el problema N+1, dispara el número de consultas y ralentiza considerablemente la carga del panel.
La solución para evitar este inconveniente es implementar eager loading. Esto permite cargar de forma anticipada las relaciones que sabes que serán necesarias, reduciendo drásticamente el número de consultas y mejorando el rendimiento general.
¿Cuándo conviene utilizar eager loading en Laravel Nova?
El eager loading en Laravel Nova resulta especialmente útil cuando necesitas manejar un gran volumen de registros junto con sus relaciones, como en listados o paneles de administración. Esta técnica permite cargar todas las relaciones necesarias en una sola consulta (o en muy pocas), evitando el temido problema de las consultas N+1, que puede afectar negativamente al rendimiento de tu aplicación.
Cuando trabajas intensivamente con datos relacionados, el eager loading no solo acelera el tiempo de respuesta, sino que también disminuye significativamente la cantidad de consultas realizadas a la base de datos, mejorando así el rendimiento global del sistema.
¿Qué es el problema N+1 en Laravel y cómo se puede solucionar?
El problema N+1 surge cuando, al trabajar con una colección de modelos, se generan consultas adicionales al acceder a sus relaciones dentro de un bucle. Por ejemplo, si obtienes 100 usuarios y luego accedes a $user->posts dentro de un bucle, Laravel ejecutará 101 consultas: una para recuperar los usuarios y otra para cada conjunto de publicaciones. Este comportamiento puede afectar gravemente el rendimiento.
Para resolverlo, puedes usar eager loading, que permite cargar las relaciones necesarias en una sola consulta. Esto se logra utilizando el método with al realizar la consulta principal (User::with('posts')->get()) o el método load si ya tienes la colección ($users->load('posts')). Además, Laravel 10 incluye el strict mode, que ayuda a detectar patrones N+1 durante el desarrollo. Herramientas como Debugbar también son útiles para analizar y reducir el número de consultas ejecutadas.
Si buscas optimizar tus paneles en Laravel Nova, Raúl López – Desarrollo Web Laravel puede ofrecerte soluciones efectivas para minimizar los tiempos de carga, incluso cuando trabajas con grandes volúmenes de datos.