Generate Angular artifacts (components, services, pipes, directives, guards, interceptors, routes, stores). Use automatically when the user asks to create any Angular code, scaffold a feature, or add a new file to an Angular project. Mirrors Angular CLI conventions.
Primary reference: https://angular.dev/llms.txt — always consult Angular documentation for current API.
app.config.ts (standalone app) vs app.module.ts (module-based app)tsconfig.json to find path aliases (@shared/*, @core/*, etc.)package.json for Angular version and installed packages (NgRx, signals API availability)jest.config.js) or Karma (karma.conf.js) is the test runnerng generateAngular 20+: Component files use
{name}.ts(no.component.suffix) with matching{name}.html,{name}.scss,{name}.spec.ts. All other artifacts retain their type suffix (.service.ts,.pipe.ts, etc.).
| Angular CLI | Plugin equivalent | Output |
|---|---|---|
ng g c {name} | /ng:generate component {name} | {name}.ts + {name}.html + {name}.scss + {name}.spec.ts |
ng g s {name} | /ng:generate service {name} | {name}.service.ts + {name}.service.spec.ts |
ng g p {name} | /ng:generate pipe {name} | {name}.pipe.ts + {name}.pipe.spec.ts |
ng g d {name} | /ng:generate directive {name} | {name}.directive.ts + {name}.directive.spec.ts |
ng g g {name} | /ng:generate guard {name} | {name}.guard.ts + {name}.guard.spec.ts |
ng g interceptor {name} | /ng:generate interceptor {name} | {name}.interceptor.ts + {name}.interceptor.spec.ts |
ng g r {name} | /ng:generate routes {name} | {name}.routes.ts |
| — | /ng:generate store {name} | NgRx feature store (actions/reducer/selectors/effects/index) |
src/app/shared/{type}s/{artifact-name}/src/app/pages/{feature}/{type}s/{artifact-name}/src/app/core/services/src/app/core/guards/ or src/app/core/interceptors/src/app/pages/{feature}/Always create an index.ts barrel in the containing directory if one does not already exist.
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
@Component({
selector: 'app-{name}',
standalone: true,
imports: [],
templateUrl: './{name}.component.html',
styleUrl: './{name}.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class {Name}Component {
// Use inject() — never constructor injection
// private readonly service = inject({Name}Service);
}
HTML template — use new Angular control flow:
<!-- @if / @for / @switch — never *ngIf / *ngFor -->
providedIn: 'root' default)import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class {Name}Service {
private readonly http = inject(HttpClient);
}
Use feature-level providers array in routes config when service must be scoped to a lazy route.
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({ name: '{name}', standalone: true, pure: true })
export class {Name}Pipe implements PipeTransform {
transform(value: unknown, ...args: unknown[]): unknown {
return value;
}
}
import { Directive, inject } from '@angular/core';
@Directive({ selector: '[app{Name}]', standalone: true })
export class {Name}Directive {
// private readonly el = inject(ElementRef);
}
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
export const {name}Guard: CanActivateFn = (route, state) => {
const router = inject(Router);
// return true | false | UrlTree
return true;
};
import { inject } from '@angular/core';
import { HttpInterceptorFn } from '@angular/common/http';
export const {name}Interceptor: HttpInterceptorFn = (req, next) => {
return next(req);
};
import { Routes } from '@angular/router';
import { {Name}Component } from './{name}.component';
export const {NAME}_ROUTES: Routes = [
{
path: '',
component: {Name}Component,
},
];
actions.ts:
import { createAction, props } from '@ngrx/store';
export const load{Name} = createAction('[{Name}] Load');
export const load{Name}Success = createAction('[{Name}] Load Success', props<{ data: {Name}[] }>());
export const load{Name}Failure = createAction('[{Name}] Load Failure', props<{ error: string }>());
reducer.ts:
import { createReducer, on } from '@ngrx/store';
import * as {Name}Actions from './actions';
export interface {Name}State {
data: {Name}[];
loading: boolean;
error: string | null;
}
const initialState: {Name}State = { data: [], loading: false, error: null };
export const {name}Reducer = createReducer(
initialState,
on({Name}Actions.load{Name}, state => ({ ...state, loading: true, error: null })),
on({Name}Actions.load{Name}Success, (state, { data }) => ({ ...state, loading: false, data })),
on({Name}Actions.load{Name}Failure, (state, { error }) => ({ ...state, loading: false, error })),
);
selectors.ts:
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { {Name}State } from './reducer';
export const select{Name}State = createFeatureSelector<{Name}State>('{name}');
export const select{Name}Data = createSelector(select{Name}State, s => s.data);
export const select{Name}Loading = createSelector(select{Name}State, s => s.loading);
export const select{Name}Error = createSelector(select{Name}State, s => s.error);
effects.ts:
import { inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, of, switchMap } from 'rxjs';
import * as {Name}Actions from './actions';
import { {Name}Service } from '../services/{name}.service';
export const load{Name}Effect = createEffect(
(actions$ = inject(Actions), service = inject({Name}Service)) =>
actions$.pipe(
ofType({Name}Actions.load{Name}),
switchMap(() =>
service.getAll().pipe(
map(data => {Name}Actions.load{Name}Success({ data })),
catchError(err => of({Name}Actions.load{Name}Failure({ error: err.message }))),
),
),
),
{ functional: true },
);
Always use takeUntilDestroyed() — never ngOnDestroy + Subject pattern:
private readonly destroyRef = inject(DestroyRef);
ngOnInit() {
this.service.data$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(data => { /* ... */ });
}
After creating any artifact in a directory, ensure index.ts exports it:
export * from './{name}.component';
export * from './{name}.service';
// etc.
any — use unknown and narrow, or define an interface@Input() and @Output() must be typedreadonly for injected dependencies and signal() values that should not be reassigned