Skip to content

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:

  1. Any component declared in an NgModule must now explicitly set standalone: false
  2. 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:

bash
ng update

This will:

  1. Add standalone: false to non-standalone components
  2. Remove incompatible imports arrays from non-standalone components
  3. Handle other v19 migration tasks

Manual Fixes

1. Add standalone: false to components

For any component declared in an NgModule, add standalone: false:

typescript
@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:

typescript
@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:

bash
# 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:

  1. Standalone components manage their own dependencies
  2. NgModule declarations require explicit non-standalone status
  3. 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

Additional Resources