惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

月光博客
月光博客
Cyberwarzone
Cyberwarzone
L
LINUX DO - 最新话题
N
News and Events Feed by Topic
T
Troy Hunt's Blog
Help Net Security
Help Net Security
S
Security @ Cisco Blogs
Google DeepMind News
Google DeepMind News
Security Archives - TechRepublic
Security Archives - TechRepublic
M
MIT News - Artificial intelligence
G
Google Developers Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V2EX - 技术
V2EX - 技术
Y
Y Combinator Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
T
Threatpost
Recent Commits to openclaw:main
Recent Commits to openclaw:main
S
SegmentFault 最新的问题
I
InfoQ
H
Hacker News: Front Page
D
Docker
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
Netflix TechBlog - Medium
AWS News Blog
AWS News Blog
Know Your Adversary
Know Your Adversary
博客园 - 【当耐特】
T
Tor Project blog
U
Unit 42
H
Heimdal Security Blog
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
P
Privacy & Cybersecurity Law Blog
PCI Perspectives
PCI Perspectives
美团技术团队
O
OpenAI News
T
Tailwind CSS Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog
GbyAI
GbyAI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
MyScale Blog
MyScale Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
loadComponent vs loadChildren in Angular 19: Choosing the Right Lazy-Loading Boundary
Sanket Bhor · 2026-06-01 · via DEV Community

There's a pattern I've been seeing more frequently across Angular codebases since standalone components became mainstream.

A team migrates away from NgModules. They discover loadComponent. It's simpler, requires less boilerplate, and feels aligned with where Angular is heading. So they start replacing loadChildren calls across the routing configuration — one by one, sometimes all at once.

The build passes. The application behaves exactly as before. Bundle reports may even suggest the migration was a success.

The problem is that routing decisions are judged by what happens immediately after deployment. Architectural decisions are judged six months later.

I've reviewed migrations where every loadChildren route was replaced with loadComponent in a single PR. The application kept working. Six months later the route structure no longer reflected the application's feature boundaries. Ownership became harder to understand. Shared concerns started leaking across routes. The routing configuration became flatter — but not simpler. One of those reviews turned into a two-sprint refactor that the team hadn't budgeted for.

Angular 19 made standalone the default. New projects no longer generate NgModules, which means loadComponent is now the first lazy-loading API many developers encounter. That makes the distinction between these two APIs more important than ever — not less.

This article is not about which API is newer. It's about understanding the architectural boundary each one creates, and why treating them as interchangeable is a mistake that compounds quietly over time.


What Angular Actually Says

The Angular routing documentation is accurate but brief on this distinction.

loadComponent lazily loads a single standalone component when its route becomes active. loadChildren lazily loads a set of child routes — typically from a separate routes file. Both use dynamic import() under the hood. Both are fully supported in modern Angular.

The documentation stops there. The architectural reasoning is left to the reader, which is where most of the confusion starts.


The Architectural Difference: Component Boundary vs Feature Boundary

The surface-level difference is obvious: one loads a component, one loads routes.

The more important difference is the scope of the lazy-loading boundary.

loadComponent creates a boundary around a single screen. When a user navigates to /help, Angular loads HelpComponent and nothing else.

loadChildren creates a boundary around a feature domain. When a user navigates to /admin, Angular loads a route configuration that may contain dozens of child routes, shared providers, feature-specific guards, and related components — all bundled together as a cohesive unit.

// loadComponent — boundary is one screen
{
  path: 'help',
  loadComponent: () => import('./help/help.component').then(m => m.HelpComponent)
}

// loadChildren — boundary is an entire feature domain
{
  path: 'admin',
  loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes)
}

Visualising where boundaries should sit makes this clearer:

Application
│
├── /help          → loadComponent   (isolated screen, no sub-routes)
├── /about         → loadComponent   (isolated screen, no sub-routes)
├── /terms         → loadComponent   (isolated screen, no sub-routes)
│
├── /admin         → loadChildren    (feature domain)
│   ├── /users
│   ├── /users/:id
│   ├── /roles
│   └── /audit
│
├── /dashboard     → loadChildren    (feature domain)
│   ├── /analytics
│   └── /reports
│
└── /checkout      → loadChildren    (feature domain — shared state, sequential flow)
    ├── /cart
    ├── /shipping
    └── /payment

The question is never "which API is more modern." The question is: where should the lazy-loading boundary exist for this part of the application?

Dimension loadComponent loadChildren
Lazy-loading scope Single component Feature route set
Chunk granularity Component-level Feature-level
Route organisation Flat Hierarchical
Shared providers Possible but duplicated across routes Grouped at feature level, scoped to feature lifetime
Route-level providers Supported, but scoping breaks down at scale Naturally scoped via parent route providers array
Guard and resolver inheritance Must be repeated per route Applied once at the feature boundary
Scalability Good for isolated pages Good for feature domains
Team ownership Per-route Per-feature file

When loadComponent Works Best

Some routes are genuinely independent. They have no sub-navigation. They don't share services with adjacent routes. They don't need their own route hierarchy.

Good candidates:

  • /help — static content, visited rarely
  • /about — no dependencies on feature services
  • /terms, /privacy — purely informational
  • /error — error boundary pages
  • A lightweight settings landing page that links out to deeper sections

For these routes, loadComponent is the right answer. There's no feature boundary to model, no shared providers to group, and no sub-routes that logically belong together.

export const routes: Routes = [
  {
    path: 'help',
    loadComponent: () => import('./help/help.component').then(m => m.HelpComponent)
  },
  {
    path: 'about',
    loadComponent: () => import('./about/about.component').then(m => m.AboutComponent)
  },
  {
    path: 'terms',
    loadComponent: () => import('./legal/terms.component').then(m => m.TermsComponent)
  }
];

No extra route file. No unnecessary abstraction. Just a lazy-loaded screen.


When loadChildren Is the Correct Architecture

Now consider an admin area. It contains user management, role configuration, audit logs, reporting, and a dashboard. These routes share services. They share guards. They have their own sub-navigation. They belong to the same business domain and are typically owned by the same team.

Here's what it looks like when loadComponent is overused on a feature domain:

// What this looks like when loadComponent is applied to a feature domain
export const routes: Routes = [
  { path: 'admin/dashboard', loadComponent: () => import('./admin/dashboard/dashboard.component').then(m => m.DashboardComponent) },
  { path: 'admin/users', loadComponent: () => import('./admin/users/users.component').then(m => m.UsersComponent) },
  { path: 'admin/users/:id', loadComponent: () => import('./admin/users/user-detail.component').then(m => m.UserDetailComponent) },
  { path: 'admin/roles', loadComponent: () => import('./admin/roles/roles.component').then(m => m.RolesComponent) },
  { path: 'admin/audit', loadComponent: () => import('./admin/audit/audit-log.component').then(m => m.AuditLogComponent) },
];

This flat structure has real costs. Guards and resolvers must be repeated on every route individually. Providers must either be hoisted to root — where they live for the entire application lifetime — or duplicated across route definitions. Child route hierarchy is gone: /admin/users/:id is now a peer of /admin/dashboard at the application level rather than a child of /admin/users. Ownership is unclear.

Here's what it should look like:

// Feature domain correctly modelled as loadChildren
export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.routes').then(m => m.adminRoutes),
    providers: [
      AdminUserService,
      AdminAuditService,
    ]
  }
];

And inside admin.routes.ts:

export const adminRoutes: Routes = [
  {
    path: '',
    canActivate: [AdminGuard],
    children: [
      { path: 'dashboard', loadComponent: () => import('./dashboard/dashboard.component').then(m => m.DashboardComponent) },
      { path: 'users', loadComponent: () => import('./users/users.component').then(m => m.UsersComponent) },
      { path: 'users/:id', loadComponent: () => import('./users/user-detail.component').then(m => m.UserDetailComponent) },
      { path: 'roles', loadComponent: () => import('./roles/roles.component').then(m => m.RolesComponent) },
      { path: 'audit', loadComponent: () => import('./audit/audit-log.component').then(m => m.AuditLogComponent) },
    ]
  }
];

This structure does several things the flat version cannot:

  • AdminGuard is applied once at the feature boundary, not repeated on five routes
  • AdminUserService and AdminAuditService are scoped to the admin feature — instantiated when the admin section loads, destroyed when the user leaves it (assuming default router configuration without a custom RouteReuseStrategy)
  • /admin/users/:id is correctly a child of /admin/users, not an application-level peer
  • The admin team owns and modifies admin.routes.ts without touching the root routing configuration
  • Route data, breadcrumb metadata, and analytics identifiers cascade naturally to all child routes

Worth calling out explicitly: loadComponent does support a providers array. The technical limitation isn't that providers are unavailable — it's that when five sibling routes all need the same service, you either duplicate the provider declaration across all five or hoist it to root. Neither is correct. loadChildren solves this cleanly because the scoping boundary and the feature boundary are the same thing.

The architectural signal is straightforward: if you find yourself writing admin/ as a prefix on five separate loadComponent routes, you've missed a feature boundary.


A Note on Chunk Count and Preloading

It's tempting to treat more lazy chunks as automatically better. I've seen teams celebrate an increase in lazy-loaded chunks without measuring the actual impact. That's optimising an assumption, not a result.

More chunks mean more network requests. Whether that matters depends heavily on your preloading strategy. With PreloadAllModules or QuicklinkStrategy, Angular preloads lazy chunks in the background after initial load — which means chunk granularity becomes less critical for perceived performance. With no preloading, a large feature chunk loaded on first navigation to /admin is a real cost.

Before restructuring routes for bundle reasons, run ng build --stats-json and load the output into Webpack Bundle Analyzer. Measure the before and after. If you haven't measured, you haven't optimised — you've just changed things.


Common Mistakes

Replacing every loadChildren call with loadComponent during a standalone migration.
This is the most common mistake I see. Standalone components and route architecture are separate concerns. A standalone component works perfectly inside a loadChildren route file. Migrating one does not require changing the other. I've reviewed PRs where an engineer replaced every loadChildren call in a single commit and labelled it a "standalone migration" — it wasn't. It was an architectural change that happened to compile cleanly.

Losing hierarchical route structure.
When loadChildren is replaced with flat loadComponent routes, child route hierarchy disappears. Guards, resolvers, and providers that once applied at the feature level must now be repeated per route. This surfaces in code review as canActivate: [AuthGuard] duplicated across every admin route — a clear sign that a feature boundary was missed.

Treating standalone components as an architecture strategy.
Standalone components improve dependency declaration and compilation. They say nothing about how routes should be organised. The routing structure decisions still belong to the engineering team.

Optimising without measuring.
Run bundle analysis before and after any routing restructure. Smaller bundles are not automatically better. More chunks are not automatically better. Your preloading strategy changes what "better" means.


When loadChildren Is Overkill

The case for loadChildren at feature boundaries holds for medium-to-large applications. It is not universally correct.

A small internal tool. A side project. A marketing site. A single-team application with eight routes. These gain little from introducing route files and feature boundaries everywhere. The abstraction costs more than it saves.

The honest rule: use loadChildren when the feature boundary is real — when there are multiple related routes, shared providers, and a clear reason to group them together. Don't introduce it to impose large-application structure on a codebase that isn't there yet. Premature route architecture is still premature optimisation.

The inflection point is usually recognisable: when you find yourself duplicating guards across related routes, or when a new developer can't tell which routes belong together by reading the root configuration, the feature boundary has been missed and loadChildren will pay for itself quickly.


What I Use in Production

On a 600+ component Angular platform serving enterprise clients, both strategies coexist and have distinct jobs.

Feature domains — client configuration, reporting, user administration, the main product dashboard — all use loadChildren. These are coherent domains with their own providers, guards, and sub-navigation. Fragmenting them into individual loadComponent calls would make the routing configuration harder to read and the feature boundaries harder to maintain. In a monorepo, these feature route files map directly to library boundaries, which means the routing structure reflects actual team ownership.

Isolated screens — the help centre, terms pages, error boundaries, and a handful of rarely visited informational pages — use loadComponent. No sub-routes, no shared dependencies, no reason to create a route file.

Nobody on the team debates the APIs in isolation. The conversation is usually about ownership, shared dependencies, and deployment boundaries. The routing decision follows from those answers.


Decision Matrix

Scenario Recommendation Reason
Help / About / Terms pages loadComponent Isolated, no sub-routes, no shared dependencies
Error boundaries loadComponent Independent, no feature services
Admin area loadChildren Feature domain with sub-routes, shared guards, shared services
Reporting dashboard loadChildren Multiple related routes, shared data services
Multi-step checkout flow loadChildren Shared state, guards, sequential child routes
User account section loadChildren Profile, billing, security — related routes with shared context
Marketing pages loadComponent Independent, no feature services
Small internal tool (<8 routes total) loadComponent Overhead of feature files not justified
Feature-rich business domain loadChildren Architecture boundary, not just a routing convenience

Final Thoughts

Most routing mistakes aren't caused by choosing the wrong API. They're caused by placing the lazy-loading boundary in the wrong place.

loadComponent works best when a route represents a genuinely independent screen — one component, no children, no shared dependencies.

loadChildren works best when a route represents a feature domain — a coherent set of routes that share providers, guards, and ownership.

The strongest Angular routing configurations use both. Not because mixing APIs is sophisticated, but because real applications contain both isolated screens and feature domains. The routing configuration should reflect that honestly.

When evaluating a route, I've stopped asking "which API should I use?" I ask: what is the actual boundary here?

If the answer is "a page," I reach for loadComponent.

If the answer is "a feature," I reach for loadChildren.

Once the boundary is clear, the API choice is obvious.


If you're in the middle of a standalone migration and replacing loadChildren calls wholesale — slow down. Ask whether each replacement is an architectural decision or a syntax preference. The answer is not always the same, and the difference matters six months from now.


References


I write about frontend problems from real projects — follow if that's useful.

If this helped, drop a ❤️ — it helps with visibility.

Connect with me: