6 nov 2023 · Actualizado 15 jul 2026

Angular @defer: Lazy Loading de Componentes Fácil

angulardeferfrontendtypescriptcontrol-flow

@defer en Angular carga componentes de forma diferida con triggers viewport, interaction e idle. Mejora la carga inicial sin cambiar TypeScript.

Podemos pensar en @defer como el setTimeout() pero @defer nos provee de más opciones y funcionalidades, por ejemplo:

setTimeout(() => { console.log("Retrasado por 1 segundo."); }, "1000");

Set timeout solo funciona en como un delay de componente usando @defer con la novedad de que podemos mostrar un placeholder durante el tiempo que indiquemos en este caso un segundo.

@defer(on viewport(myPlaceholder), on timer(1s)) { <app-child /> } @placeholder(minimum 1000ms) { <div #myPlaceholder>...</div> }

@defer tiene más casos de usos, ya que además se incluye otras etiquetas que son de ayuda y que además son explícitas en su uso, como ser:

  • @placeholder
  • @error
  • @loading

Además de combinaciones porque podemos usar junto a un varios triggers(disparadores):

  • when isVisible
  • on idle
  • on inmediate
  • on interaction(trigger)
  • on timer(time)
  • on hover(trigger)
  • on viewport(container)

Los triggers, uno por uno

When

Es una condición que puede ser usada junto a una variable, una función, un valor que paso por un pipe o etc. Los Observables y AsyncPipes no pueden ser usados por el momento.

On idle:

Este es un comportamiento por defecto y se ejecuta cuando la app esté inactiva.

On immediate:

Este trigger se activa cuando él, témplate(plantilla) se renderiza.

On timer(1s):

Es un trigger basado en setTimeout el cual puede usarse en segundos usando la s o en milisegundos usando ms después de la cantidad.

On interaction():

Al hacer clic en la platilla de referencia, precisamente en la referencia de plantilla #trigger como por ejemplo:

<button #trigger class="btn btn-red">Botón de Acción <button /></button>

On hover(trigger):

Al hacer hover en la platilla de referencia, precisamente en la referencia de plantilla #triggerHover como por ejemplo:

<button #triggerHover class="btn btn-red hover:bg-red"> Botón de Hover <button /> </button>

On viewport(contenedor):

Al renderizar el viewport de la referencia #contenedor, por ejemplo la página se está renderizando, por lo que al llegar a la etiqueta #contenedor debe hacer algo o ejecutar una función.

Podemos usarlo todos a la vez simplemente separándolos por una coma de la siguiente manera:

@defer (when isVisible() && isAuth , prefetch on immediate; prefetch when isDataLoaded()) { <componente-grande"/> } @placeholder (minimum 500ms){ Placeholder content! } @loading (minimum 1s; after 100ms){ Loading... } @error { Loading failed :( }

Por lo que podemos usar un defer que al retornar true que está visible y que esté autenticado isAuth pre cargue inmediatamente cuando la plantilla esté lista y que pre cargue una función específica, la cual será isDataLoaded(); como puedes ver está el bloque @placeholder el cual como su nombre lo indica nos sirve para poner contenido estático, @loading en el cual podemos poner un skeleton loader o css de carga para que visualmente el usuario sepa que se está cargando y el @error podemos utilizarlo para mostrar un mensaje o acciones.

Además, todo esto lo podemos combinar con el nuevo Control Flow y combinarlo con @if, @else, @for anidarlo, usar un @defer y muchas combinaciones más para hacer de la experiencia algo más ameno.

defer y for:

@defer dentro de un @for

@for (libro of libros) { @defer { <componente-grande /> } }

@for dentro de un @defer

@defer { @for (libro of libros) { <componente-grande /> } }

En el primer ejemplo, por cada libro dentro del @for se creará una embedded view y una embedded view anidada por cada @defer lo que nos dará la cantidad de libros.length _ 2 que serían las embedded views del @for y libros.length en el @defer por lo que podemos asumir que si tenemos 100 libros tendremos 100 _ 2 + 100,

Ahora en el segundo ejemplo solo hay una interacción del @defer por lo que las embedded view serán solo una y las del @for serán libros.legth + 1

Por lo que la decisión dependerá de como queremos resolver o usarlo y si cada uno de libros en el for contienen componentes grandes o queremos agregar interacción al @defer como ser un loading o cualquiera de los ejemplos anteriores.

Bonus

Como esto funciona en el compilador, pues simple:

@defer { <componente-grande /> }
function defer_for_block { return [ () => import('./componente-grande') ] }

Esta solo es una de las muchas nuevas funcionalidades que trae el renacimiento de Angular.

Escrito por

Antonio Cárdenas

Google Developer Expert en Angular · Perfil GDE verificado · Perfil de Google Developers

Mi escritura técnica llega a más de 100,000 desarrolladores en inglés y español. He migrado aplicaciones Angular de producción desde la v8 hasta la v22 — todo lo que publico nace de trabajo real en proyectos, no de releer la documentación.

Preguntas frecuentes

Preguntas frecuentes

¿Qué es @defer en Angular y para qué sirve?

@defer es un bloque de Angular 17+ que permite lazy loading declarativo de componentes directamente en la plantilla. Divide automáticamente el bundle y carga el contenido de forma diferida según triggers como viewport, interaction, timer o idle. Es la alternativa declarativa a los import() dinámicos en TypeScript.

¿Cuáles son los triggers disponibles en @defer?

Los triggers de @defer son: on idle (cuando el navegador está inactivo, comportamiento por defecto), on immediate (al renderizar la plantilla), on viewport(ref) (cuando el elemento entra en el viewport), on interaction(ref) (al hacer clic), on hover(ref) (al pasar el cursor), on timer(1s) (después de un tiempo), y when condicion (expresión booleana personalizada).

¿Cuál es la diferencia entre @placeholder y @loading en @defer?

@placeholder muestra contenido estático mientras el componente diferido no ha comenzado a cargarse — es lo que ve el usuario al principio. @loading muestra contenido durante la descarga activa del chunk. Configura @placeholder(minimum 500ms) para evitar parpadeos, y @loading(after 100ms; minimum 1s) para controlar cuándo y por cuánto tiempo aparece el indicador de carga.

¿@defer afecta al SEO y al Server-Side Rendering?

El contenido dentro de @defer no se renderiza en el servidor por defecto, lo que puede afectar al SSR y al SEO si se usa para contenido crítico. Para contenido importante para buscadores, usa @placeholder con el contenido visible como fallback, o configura Angular SSR para renderizar el bloque diferido en el servidor. Para widgets secundarios como comentarios o mapas, @defer es ideal.

¿Desde qué versión de Angular está disponible @defer?

@defer se introdujo en Angular 17 (noviembre 2023) como parte de las Deferrable Views. Es parte del renacimiento de Angular (Angular Renaissance) junto con el nuevo Control Flow y los Signals. Está estabilizado como API pública desde Angular 18 y es ampliamente recomendado para optimizar el rendimiento de carga inicial.

Sigue leyendo

¿Construyendo algo con Angular?

Escribo sobre arquitectura en Angular, Signals y el tooling a su alrededor — guías de migración, rutas reales de actualización y los detalles que la mayoría de artículos se saltan.

Ver todos los artículosAcerca de mí

Más del blog