Use automatic migration to make your angular codebase standalone. Or follow a manual step-by-step migration, if needed.
To use standalone components, add the standalone: true
property to the component decorator and explicitly import necessary Angular features in the imports array. For instance, if your component utilizes NgIf
, include it in the imports
array.
When bootstrapping a standalone component, utilize the bootstrapApplication
function, replacing the bootstrapModule
function.
Existing Angular applications can be incrementally migrated to standalone components using the Angular CLI schematic ng generate @angular/core:standalone
. This schematic assists in converting existing code and transitioning to the standalone bootstrapping API.
[00:00] Modern Angular has introduced standalone components and standalone APIs, which allow us to remove entirely ng modules from our Angular applications. So one of the consequence is that Angular application is not going to bootstrap an Angular NG module [00:19] from now on, but it's going to bootstrap a given component directly. So why would one remove NG modules from their applications? First of all, one abstraction gets removed. We don't need to think about the imports, export declarations, etcetera, especially that we have imports and export natively [00:40] within our ECMAScript standard. So that's basically a redundancy. Another reason is that deferrable views allow us to implement lazy loading very, very fast and conveniently, and they work only with standalone components. Finally, Angular introduced the [01:00] standalone true as the default from version 19. So let's see how would a manual migration lock in practice. So here we've got the office listing component, and this components template is using a child component, which is the office details component. So the [01:19] flag that determines being standalone or not is the standalone true, again, from Angular 19. This is the default. So what changes is that this is not meant to be part of an NG module anymore from now on. So when we move to offices module, we'll see that it's [01:39] not possible to list it within the declarations and even more, it's not possible to export it from here. So either if we want to have this component being used by other components, pipes, directives, whatever, within this ng module, then we would basically put it over here within the imports. [01:59] But this is not our case, and we can remove it entirely. So our offices module is up and running. As we can see, we're getting quite a lot of errors over here. So let's go through these errors step by step. We can see that the office listing component HTML, the one that we have at the [02:19] bottom over here, is crying about the async pipe not being available. So since this component is stand alone, we need to directly import everything that it is going to use. And in this case, the async pipe is something that we need to use. So [02:38] either we can import the entire common module, which is possible, or if we want to go more granular, we can import the async pipe. That's basically up to us. How much granular do we want to walk? So let's comment out the async pipe. Now we've got the error is [02:58] that ID corpo office details is not a known element. So let's again walk into the template of our components. So here, Angular compiler is crying that this component is not known. So why is it not known? Before, our component could have seen everything that [03:18] was available within the NG module. In our case, that was the offices module, the one. So right now, offices details component is not available. So what we need to do is, again, import the thing that we need. So in our case, this is the office details [03:38] component, but office details component is not yet a standalone component because we would need to look it up. So this is standalone false as for now. So what we would need to do is to load the office module. So the thing that basically includes the thing that we need. So one more thing that [03:58] we need to do in order to make IT Corp Office available is that when we move to the modules, then we need to make the office details component also available to the outside. So right now, the office listing components template can see the office details [04:18] child component. But as we can see on the right hand side, there is something going wrong within the console. And here we have the uncaught reference error cannot access some routing module before initialization. So it could happen that we have circular dependencies or any [04:37] other consequences of removing ng modules. So in this case, what is going on is that if we take a look at the offices module, then the trouble is that some of the references are getting imported too early. And I just wanted to showcase the error. So in our case, we just need to remove [04:57] this import here, and our application is up and running. So as we can see, there is quite a lot of manual work that needs to be done. So let's run the migration automatically. So in this case, again, and you generate Angular slash core, and our migration [05:17] is called standalone. What is going to be different compared to other migrations is that there are going to be 3 steps that we need to execute sequentially. The first one is convert all components, directives, and pipes to standalone. So this is going to be pretty simple. Again, no options apart [05:37] from just the path. So if we now take a look at how does the office component look like, the one that we've seen before is that it has become stand alone. If we also take a look at the offices module, we can see that there is more changes than what we've seen before. So let's take a look at [05:57] what happened. First, there were declarations for the office listing, office details, and office image. This is the one that we have removed manually, but these are the ones that we have remained. So as we can see, there are no declarations anymore. So NG modules, as you can see, are not yet [06:17] removed. Only the components, directives, and pipes have been made standalone. Now there are potentially more imports that we can see. So so far we've had the common module. The office routing has been commented out by us, and there was also shared module. But what we can also see [06:37] is that there are some more imports over here so that if anybody is using this NG module, the number of breaking changes would be limited as much as possible. And finally, the exports are left as they were before. What is important and very convenient is that Angular, [06:57] while doing the migration, is going to analyze the content of whatever is being used within a component. So in this case, let's take a look at the employees detail component or rather the HTML file of this component, and let's also move it to the side. And within the employee [07:16] details component, we are using the currency pipe and the date pipe. And as we can see, since the component has become standalone, the currency pipe and the date pipe would not be visible. So something would have to be imported. So either that would be the corresponding module or if we want to go more granular, and that's the [07:36] case for the automatic migration, they are explicitly imported within the components definition. So that's one example. If we take a look at the employees listing component, yes, and its corresponding HTML, then we would see that it's [07:56] using the router link and the router link active. And, again, the corresponding TS file is importing the router link active and the router link. So if we are using anything within our component that needs to be exposed within the imports, the automatic migration [08:16] is going to do this for us. So before we move forward, let's note that we have quite a lot of local changes, and we have still other 2 steps ahead of us. So in case anything goes wrong, and theoretically, it could, it's just a good idea to make some kind of a snapshot [08:36] or a branch, commit, or basically use the git stage, anything that it would be simple or convenient for us to, roll back to. So now when we have our, let's say, backup, we can continue with a standalone migration and walk into the second phase, which is remove [08:56] unnecessary module classes. So what we can see is that only 2 of the modules have been removed, and there are other remaining modules which have been updated. So let's take a look at why didn't office module get removed. So here we can see that there are a couple of [09:16] imports, and there is also one export. So we can basically try to comment these out, as well as commenting out these imports, and see whether this is going to make the migration remove this NG module entirely, and we can see that, yes, [09:36] if we only apply the same principle, we're going to get these NG modules wiped out. So let's once again run this standalone migration. Let's remove. At this point, the only thing that we've got is the app module ts. And what is it's using is the [09:56] finances module. So let's take a look at it. And let's apply the same principle. So basically wiping out everything from this module and rerunning the migration again. And that makes the finances module being removed. [10:16] Finally, let's run the last step, which is going to modify the main TS file replacing bootstrapping the module with bootstrapping the component. So again, n g generate standalone and bootstrap the application using standalone APIs. Let's run this. And here we've got the [10:35] result. So now the bootstrap application is accepting a component that is going to bootstrap the entire application, and it also accepts the providers. So first of all, there are some providers that we just need in our environment, and some of them might go into the environment [10:55] injector. But also, there might be some providers which are some leftovers from the modules that we haven't removed yet. And even though you could expect that at this point all of the ng modules would be removed, this is expected indeed because applications could be really big and complex and most of [11:15] the times you are going to apply these migrations incrementally directory by directory or a module by a module, whatever the structure is. So the fact that we can do this incrementally is actually very, very useful.