Why NgModules Existed — and What Replaced Them In short: was doing four separate jobs at once. Each job now has its own replacement. Knowing which job your module was doing is what makes it safe to delete. When people move away from modules, the first instinct is to treat them as pointless extra code that Angular finally admitted was not needed. That view makes the job harder than it needs to be. was not one thing. It was four unrelated jobs sharing one place, and each has a different replacement. Delete a module without knowing which job it was doing, and you will delete something that mattered. The problem modules solved Angular has to work out what your tags mean. When it sees in a template, it has to know which class that is. Normal TypeScript imports cannot help here. Templates are text. Nothing in your file mentions the component that the template uses. There is no import to follow. was the answer. It was a list saying: these components exist, these can see each other, these can be seen from outside. That is four jobs in one object. Job 1: Working out tags — now the component's own and told the compiler which tags were available. A standalone component says this itself: This is better, and not only because it is shorter. The list now sits where it is used , so it can be checked where it is used . An unused item in a component's is an error you see when you build. An unused item in a module's was invisible. It also means Angular can remove unused code properly. Importing pulls in exactly what its template needs — not everything its module happened to list. disappears completely, because and are now part of the template language instead of directives you have to import. Job 2: Providing services — now and on a module registered services. Two things replaced it. For normal services, had already made module providers unnecessary years ago. v22 makes it even shorter: For setting up a library — the old pattern — the replacement is a function: fits together better than ever did. And each is separate, so unused ones can be dropped from your build. If you do not ask for view transitions, that code is not in your app. could never do that, because a module is an object the build tool cannot pull apart. Job 3: Loading code on demand — now Routes used to load a module. Often the module existed mainly to be something you could load: still exists for loading a set of routes, but it now returns routes directly: And with , loading on demand is not tied to routing at all. Any part of a template can do it. That is Chapter 3. Job 4: Grouping related code — now just folders People forget this job, and it is why some teams feel a loss when modules go. A module was documentation. It drew a line around a feature and said these things belong together . Nothing in the framework replaces this, because nothing needs to. Folders do it: The grouping is still there. You just no longer have to keep a list in step with it. The one thing you really do lose Modules could keep things private . Anything not in could not be reached from outside, and the compiler checked that for you. Standalone has no equal. Any exported class can be imported by any file. If you used module boundaries to stop teams reaching into each other's code, you now need a tool to do that job — an ESLint rule, Nx tags, or TypeScript project references. For most apps this was never real anyway. For a big shared codebase with several teams, replace it on purpose rather than finding out later that the wall is gone. "But weren't modules just extra typing?" They were solving a real problem — one most frameworks do not have. The fact people miss: Angular templates are text. React never had this problem, because JSX is the reference — is found through the normal import list. was Angular's answer to "what does this tag mean?" It was not red tape. It was a lookup table. What changed is not that the problem went away. It is that the list on does the same job in a better place. The trap: if you treat modules as pure noise, you will delete one and lose something. Work through the four jobs on purpose. Cheat sheet The four jobs and what replaced them: part Was doing Now --- --- --- Telling the compiler a component exists Nothing — components do it themselves Letting others see it The list on whoever uses it Bringing in what others exported The list on Registering services / / route providers Naming the first component (being loadable) The target of or a routes file (grouping code) Documentation Folders (keeping things private) Compiler-checked boundaries ESLint / Nx tags — the one real loss Common swaps: Replacing the privacy you lose: Keep a module only when: you publish a library that older apps use, or you are part-way through moving. Not for "we like the structure" — folders do that. The architect's view Do not migrate modules mechanically. Go through the four jobs and decide each one deliberately, because three of them have a clear replacement and the fourth does not. Jobs…