Angular @defer en 2026: carga diferida declarativa y rendimiento
Guia completa sobre los bloques @defer de Angular para carga diferida declarativa. Analisis de disparadores, prefetching, hidratacion incremental, comportamiento SSR y patrones de rendimiento en produccion. Incluye preguntas de entrevista tecnica.

Los bloques @defer de Angular resuelven un problema que la carga diferida basada en el router nunca pudo abordar: cargar componentes, directivas y pipes individuales bajo demanda sin necesidad de reestructurar la aplicacion en rutas separadas. Introducidos en Angular 17 y estabilizados a lo largo de Angular 22, los bloques @defer convierten lo que antes requeria importaciones dinamicas, flags con *ngIf y configuracion manual de webpack en un unico bloque declarativo dentro del template.
Antes de @defer, la optimizacion de rendimiento en Angular dependia exclusivamente de la division a nivel de rutas. Los componentes pesados que habitaban dentro de una misma ruta (graficos interactivos, editores de texto enriquecido, paneles de configuracion avanzada) se descargaban completos junto con el bundle de la ruta, sin importar si el usuario llegaba a interactuar con ellos. Esta limitacion generaba arquitecturas artificiales donde funcionalidades se separaban en rutas independientes unicamente por motivos de rendimiento, no por logica de negocio.
Con @defer, Angular ofrece una solucion nativa y declarativa que opera a nivel de componente individual, permitiendo que cada pieza de la interfaz defina sus propias condiciones de carga sin afectar la estructura de navegacion de la aplicacion.
@defer instruye al compilador de Angular para separar los componentes envueltos en chunks de JavaScript independientes, que se cargan unicamente cuando se cumple una condicion de disparo. El navegador descarga menos JavaScript inicial, mejorando el Largest Contentful Paint (LCP) y el Time to First Byte (TTFB) sin necesidad de configuracion manual de code-splitting.
Como funciona @defer internamente
Cuando el compilador de Angular encuentra un bloque @defer, extrae cada componente standalone, directiva y pipe contenido en el en un chunk separado. El bundle principal se distribuye sin estas dependencias. En tiempo de ejecucion, Angular evalua la condicion de disparo y descarga el chunk correspondiente mediante una llamada dinamica import().
El bloque soporta cuatro sub-bloques que controlan lo que el usuario ve durante el ciclo de vida de la carga:
@defer (on viewport) {
<analytics-dashboard />
} @placeholder {
<div class="h-64 bg-muted animate-pulse"></div>
} @loading (minimum 200ms) {
<loading-spinner />
} @error {
<p>Failed to load the dashboard. Please refresh.</p>
}@placeholder se renderiza antes de que el disparador se active. @loading aparece mientras el chunk se descarga, con una duracion minimum opcional para evitar parpadeos. @error captura errores de red o fallos en la carga del chunk. El parametro minimum en @loading previene un destello del spinner cuando el chunk se carga rapidamente desde cache.
Una restriccion fundamental: toda dependencia dentro de @defer debe ser standalone. Los componentes no-standalone declarados en un NgModule no pueden diferirse y se cargaran de forma eager independientemente del bloque @defer que los envuelva. Esta restriccion refuerza la direccion arquitectonica de Angular hacia componentes standalone como unidad base de composicion.
Tipos de disparadores: control sobre cuando cargar componentes
Angular ofrece siete disparadores integrados, cada uno orientado a una estrategia de carga diferente. Multiples disparadores pueden combinarse con punto y coma y se evaluan como condiciones OR.
// Loads when the browser goes idle (default)
@defer {
<recommendation-engine />
}
// Loads when the element enters the viewport
@defer (on viewport) {
<customer-reviews [productId]="product.id" />
}
// Loads on click or keydown
@defer (on interaction) {
<product-configurator />
} @placeholder {
<button>Configure this product</button>
}
// Loads on mouseenter or focusin
@defer (on hover) {
<quick-preview />
}
// Loads after 3 seconds
@defer (on timer(3s)) {
<chat-widget />
}
// Loads immediately after initial render
@defer (on immediate) {
<notification-center />
}El disparador on viewport utiliza internamente la Intersection Observer API. El disparador on idle delega a requestIdleCallback, lo que lo convierte en la opcion mas segura por defecto para contenido debajo del fold. El disparador on timer acepta duraciones en milisegundos (500ms) o segundos (3s).
La eleccion del disparador correcto depende del contexto de uso. Para contenido que el usuario eventualmente vera al hacer scroll, on viewport es la opcion natural. Para funcionalidades que requieren accion explicita del usuario (formularios, configuraciones, paneles de exportacion), on interaction evita descargas innecesarias. Para componentes secundarios que mejoran la experiencia pero no son criticos (widgets de chat, centros de notificaciones), on timer o on idle distribuyen la carga sin saturar la conexion.
El disparador when para condiciones reactivas
Mas alla de los disparadores basados en eventos, when acepta cualquier expresion booleana, incluyendo lecturas de signals:
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
<advanced-analytics />
} @placeholder {
<button (click)="showAdvanced.set(true)">Show advanced analytics</button>
}Combinar on y when es valido. Angular los trata como OR: el bloque se carga cuando cualquiera de las dos condiciones se cumple. Este patron resulta especialmente util cuando se trabaja con el sistema reactivo de Angular signals, ya que permite que la carga diferida responda al estado de la aplicacion sin suscripciones manuales ni observables adicionales.
Prefetching: separar la descarga de la visualizacion
El prefetching desacopla el momento en que el chunk se descarga del momento en que el componente se renderiza. Esta separacion elimina la latencia percibida al descargar el JavaScript antes de que el usuario lo necesite.
@defer (on interaction; prefetch on idle) {
<account-settings />
} @placeholder {
<button>Open settings</button>
}En este patron, el navegador descarga el chunk de account-settings durante el tiempo idle. Cuando el usuario hace clic, el componente se renderiza de forma instantanea porque el codigo ya esta disponible en memoria. El prefetching acepta los mismos tipos de disparadores que la clausula principal on.
Un patron frecuente en dashboards consiste en hacer prefetch de componentes pesados durante idle mientras se difiere el renderizado hasta la entrada en el viewport:
@defer (on viewport; prefetch on idle) {
<chart-widget [data]="salesData()" />
} @placeholder (minimum 100ms) {
<div class="h-48 bg-muted rounded-none"></div>
}El parametro minimum en @placeholder previene un destello de layout cuando el usuario hace scroll rapido y el componente diferido se carga casi de inmediato.
¿Listo para aprobar tus entrevistas de Angular?
Practica con nuestros simuladores interactivos, flashcards y tests técnicos.
@defer y el renderizado del lado del servidor (SSR)
En el servidor, los bloques @defer renderizan el contenido de @placeholder por defecto. El componente diferido nunca se renderiza en el servidor. Este comportamiento es intencional: la descarga del chunk solo tiene sentido en el contexto del navegador.
Para contenido critico en SEO, esto significa que @placeholder debe contener HTML semanticamente significativo, no solo un spinner:
@defer (on viewport) {
<comment-section [postId]="post.id" />
} @placeholder {
<section aria-label="Comments">
<h2>Comments</h2>
<p>Loading comments...</p>
</section>
}Los motores de busqueda indexan el contenido del placeholder durante el SSR. Un placeholder descriptivo garantiza que la pagina se mantenga semanticamente completa para el rastreo. Es importante considerar que si el componente diferido contiene informacion relevante para el posicionamiento, el placeholder debe ofrecer al menos la estructura HTML esperada con atributos ARIA apropiados y encabezados semanticos.
Esta caracteristica tiene implicaciones directas en la arquitectura de la aplicacion: los componentes que contienen contenido indexable deben disenar sus placeholders con la misma atencion que el componente final, incluyendo microdatos o metadatos estructurados cuando corresponda.
Hidratacion incremental con @defer
Angular 19 introdujo la hidratacion incremental en developer preview, y Angular 22 la estabiliza como funcionalidad lista para produccion. La hidratacion incremental extiende @defer con un disparador hydrate que controla cuando un componente renderizado en el servidor se vuelve interactivo en el cliente.
@defer (hydrate on viewport) {
<product-gallery [images]="product.images" />
}
@defer (hydrate on interaction) {
<product-reviews [productId]="product.id" />
}A diferencia del @defer estandar, la hidratacion incremental renderiza el HTML completo del componente en el servidor. El cliente recibe el markup completo pero omite la hidratacion del componente hasta que el disparador se activa. El resultado: el navegador pinta la pagina completa de inmediato, pero la ejecucion de JavaScript se difiere hasta que realmente se necesita.
Con hydrate on viewport, el servidor genera el HTML completo de la galeria de productos, pero el JavaScript necesario para la interactividad solo se carga y ejecuta cuando el elemento entra en el viewport. Con hydrate on interaction, las resenas aparecen como HTML estatico hasta que el usuario interactua con ellas. Este patron reduce drasticamente el Total Blocking Time (TBT) en paginas con multiples componentes pesados.
El equipo de Angular reporta mejoras consistentes del 40-50% en las puntuaciones de LCP al utilizar hidratacion incremental en paginas con contenido denso. Angular DevTools en la version 22 visualiza los estados de hidratacion (pendiente, hidratado, error) directamente en el inspector de componentes, facilitando la depuracion durante el desarrollo.
Patrones del mundo real y estrategia de rendimiento
Patron 1: Dashboard pesado con multiples paneles diferidos
Los dashboards representan el caso de uso ideal para @defer porque tipicamente contienen multiples widgets que el usuario no necesita de forma simultanea. Cada panel se carga de forma independiente cuando entra en el viewport, mientras que las acciones menos frecuentes como la exportacion de datos se cargan solo ante la interaccion explicita del usuario.
<div class="grid grid-cols-2 gap-4">
@defer (on viewport; prefetch on idle) {
<sales-chart />
} @placeholder {
<skeleton-card height="300px" />
}
@defer (on viewport; prefetch on idle) {
<user-activity-feed />
} @placeholder {
<skeleton-card height="300px" />
}
@defer (on interaction) {
<export-panel />
} @placeholder {
<button>Export data</button>
}
</div>Cada panel se carga de forma independiente. El panel de exportacion permanece sin cargar hasta que el usuario lo solicita de forma explicita, ahorrando la descarga completa de un chunk para los usuarios que nunca exportan datos.
Patron 2: Carga condicional de funcionalidades con signals
Este patron combina @defer con el estado reactivo de Angular signals para cargar funcionalidades premium solo cuando el usuario tiene la suscripcion correspondiente.
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
<ai-assistant />
} @placeholder {
<upgrade-banner />
}Los usuarios del plan gratuito nunca descargan el chunk del asistente de inteligencia artificial. El banner de actualizacion cumple una doble funcion como placeholder y como elemento de conversion, maximizando el valor de cada byte transferido.
Errores comunes que conviene evitar
Anidar bloques @defer con el mismo disparador provoca descargas simultaneas de chunks, anulando el beneficio de la carga progresiva. Es preferible escalonar los disparadores entre bloques anidados:
// Avoid: both fire on idle simultaneously
@defer {
@defer {
<nested-heavy-component />
}
}
// Better: outer on idle, inner on viewport
@defer (on idle) {
<wrapper-component />
}
// Inside wrapper-component template:
@defer (on viewport) {
<nested-heavy-component />
}La solucion consiste en asignar disparadores distintos a cada nivel de anidacion. El componente exterior se carga en idle y el interior espera a estar visible en el viewport, creando una cascada de carga controlada y predecible.
Otro error frecuente: utilizar @defer para componentes que forman parte del camino critico de renderizado. Diferir contenido above-the-fold incrementa el LCP porque el navegador debe descargar y ejecutar el chunk antes de pintar el contenido visible. @defer debe reservarse para contenido debajo del fold o activado por el usuario.
@defer vs lazy loading basado en el router
El lazy loading basado en el router y @defer se complementan entre si. El router divide a nivel de ruta, difiriendo modulos de funcionalidad completos. @defer divide dentro de un template, difiriendo componentes individuales.
| Aspecto | Lazy Loading por Router | @defer |
|--------|-------------------|--------|
| Granularidad | Nivel de ruta | Nivel de componente |
| Disparador | Evento de navegacion | viewport, idle, interaction, hover, timer, condicion |
| Comportamiento SSR | Renderizado completo en servidor | Placeholder en servidor |
| Requiere standalone | No (funciona con NgModules) | Si (solo standalone) |
| Prefetching | preloadingStrategy | Clausula prefetch on |
| Caso de uso | Modulos de funcionalidad, paginas | Widgets, paneles, UI condicional |
Una aplicacion bien optimizada utiliza ambos enfoques de manera conjunta: lazy loading por router para areas funcionales de alto nivel (administracion, reportes, configuracion) y @defer para componentes pesados dentro de esas areas. Ambas estrategias operan en niveles de granularidad distintos y no compiten entre si.
Preguntas de entrevista sobre Angular @defer
Las entrevistas tecnicas cubren cada vez con mayor frecuencia los bloques @defer a medida que se consolidan como pieza central de la estrategia de rendimiento en Angular. Los siguientes patrones aparecen regularmente en preguntas de entrevista Angular.
P: Que sucede si un componente no-standalone se coloca dentro de @defer?
El componente se carga de forma eager independientemente del bloque @defer. El compilador de Angular no puede extraer componentes declarados en un NgModule en chunks separados. No se lanza ningun error, pero la optimizacion falla de manera silenciosa. Esta es una de las razones principales por las que la migracion a componentes standalone resulta fundamental para aprovechar las funcionalidades modernas del framework.
P: Como se comporta @defer durante el SSR?
El servidor renderiza el contenido de @placeholder. El componente diferido nunca se renderiza en el servidor. La hidratacion ocurre en el cliente cuando el disparador se activa (o mediante hydrate on para hidratacion incremental). Por esta razon, el placeholder debe contener HTML semantico que aporte valor tanto a los usuarios como a los motores de busqueda.
P: Se puede usar @defer con la estrategia de deteccion de cambios OnPush?
Si. @defer es una funcionalidad a nivel de template y funciona con cualquier estrategia de deteccion de cambios. El componente diferido respeta su propia configuracion de change detection una vez cargado. Para profundizar en este tema, el modulo de deteccion de cambios cubre los distintos mecanismos disponibles y sus implicaciones en el rendimiento.
P: Cual es la diferencia entre on idle y on immediate?
on idle espera a que el navegador termine todo el trabajo pendiente mediante requestIdleCallback. on immediate se activa justo despues de que Angular completa el pase de renderizado inicial, sin esperar el estado idle. En la practica, on immediate resulta util para componentes que deben cargarse lo antes posible pero que no necesitan estar en el bundle principal, mientras que on idle prioriza la experiencia del usuario al no competir con tareas criticas del navegador.
Para una preparacion mas amplia de entrevistas Angular, se recomienda revisar el modulo de Angular signals y el modulo completo de preguntas de entrevista sobre standalone components.
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
Conclusion
Los puntos fundamentales para consolidar el conocimiento sobre @defer:
@defersepara componentes standalone en chunks independientes que se cargan bajo demanda, reduciendo el tamano del bundle inicial sin reestructurar rutas- Siete tipos de disparadores (
idle,viewport,interaction,hover,timer,immediate,when) cubren toda estrategia de carga, desde pasiva hasta dirigida por el usuario prefetch ondesacopla la descarga del chunk del renderizado del componente, eliminando la latencia percibida en componentes activados por el usuario- La hidratacion incremental (
hydrate on) renderiza el HTML completo en el servidor mientras difiere la ejecucion de JavaScript al cliente, logrando mejoras del 40-50% en LCP en paginas con contenido denso - El contenido de
@placeholderse renderiza durante el SSR y debe ser semanticamente significativo para SEO y accesibilidad @defercomplementa el lazy loading basado en el router: rutas para division a nivel de funcionalidad,@deferpara division a nivel de componente dentro de los templates- Los componentes no-standalone no pueden diferirse y se cargaran de forma eager de manera silenciosa
¡Empieza a practicar!
Pon a prueba tu conocimiento con nuestros simuladores de entrevista y tests técnicos.
Etiquetas
Compartir
Artículos relacionados

Angular 19 Zoneless: Rendimiento y Deteccion de Cambios Sin Zone.js
Guia completa sobre la deteccion de cambios zoneless en Angular 19, 20 y 21. Incluye configuracion de provideZonelessChangeDetection, migracion de Zone.js a Signals, SSR sin Zone.js con PendingTasks, benchmarks de rendimiento, reactive forms con toSignal y cronograma de estabilizacion hasta Angular 21.

Componentes Standalone en Angular: Migracion desde NgModules y Buenas Practicas en 2026
Guia completa para migrar aplicaciones Angular de NgModules a componentes standalone. Incluye el proceso CLI en 3 pasos, lazy loading con loadComponent, manejo de SharedModules, pruebas unitarias, optimizacion de rendimiento y mejores practicas para desarrollo standalone-only en 2026.

Preguntas de entrevista Angular 19: Signals, SSR y conceptos imprescindibles
Las preguntas de entrevista Angular 19 más frecuentes: Signals, hidratación incremental, detección de cambios sin Zone.js y nuevas APIs reactivas con ejemplos de código y respuestas esperadas.