Angular Component Standalone Default Change in v19
Problem Statement
After updating Angular to version 19, many developers encounter two related errors:
Component AppComponent is standalone, and cannot be declared in an NgModule
or
'imports' is only valid on a component that is standalone.
These errors occur because Angular 19 changed the default component behavior. Previously in v18, components were not standalone by default (standalone: false
). Now in v19, all components are standalone by default (standalone: true
). This means:
- Any component declared in an
NgModule
must now explicitly setstandalone: false
- Non-standalone components cannot use the
imports
array (only valid for standalone components)
Solution
Best Practice: Use Angular Update Migration
Run the official Angular migration command to automatically fix compatibility issues:
ng update
This will:
- Add
standalone: false
to non-standalone components - Remove incompatible
imports
arrays from non-standalone components - Handle other v19 migration tasks
Manual Fixes
1. Add standalone: false
to components
For any component declared in an NgModule
, add standalone: false
:
@Component({
standalone: false, // Required for non-standalone components
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {}
2. Remove imports
from non-standalone components
Non-standalone components (those with standalone: false
) cannot have an imports
array. Remove them entirely:
@Component({
standalone: false,
imports: [CommonModule], // REMOVE THIS LINE
// ...
})
export class NonStandaloneComponent {}
Migration Script for Large Projects (Use with Caution)
For projects with many components, this Unix script adds standalone: false
to components without existing imports:
# Components
find ./src -name "*.component.ts" -exec grep -L "imports:" {} \; | xargs grep -l "@Component" | grep -L "standalone:" | xargs sed -i '' -E 's/@Component\(\{/@Component({\n standalone: false,/g'
# Directives
find ./src -name "*.directive.ts" -exec grep -L "imports:" {} \; | xargs grep -l "@Directive" | grep -L "standalone:" | xargs sed -i '' -E 's/@Directive\(\{/@Directive({\n standalone: false,/g'
# Pipes
find ./src -name "*.pipe.ts" -exec grep -L "imports:" {} \; | xargs grep -l "@Pipe" | grep -L "standalone:" | xargs sed -i '' -E 's/@Pipe\(\{/@Pipe({\n standalone: false,/g'
WARNING
Backup your code before running scripts!
macOS: Use sed -i '' ...
Linux: Use sed -i ...
without ''
Key Architecture Changes
These changes occur because Angular is shifting toward a standalone-first architecture:
- Standalone components manage their own dependencies
NgModule
declarations require explicit non-standalone status- Angular recommends using standalone components for new projects
For mixed architectures:
- Standalone components: Use
imports
array - Non-standalone components: Must be declared in an
NgModule
- Combine both approaches with
imports: [ModuleContainingComponents]
in standalone components