Hiprup

What are Core and Shared modules, and when do you use them?

Two conventional Angular module types for organizing larger apps. The standalone migration is making them less common, but still good interview knowledge.

CoreModule — singletons that load once at app startup: auth service, HTTP interceptors, header/footer, error handlers. Imported only by AppModule.

SharedModule — reusable components, directives, pipes used in many feature modules: buttons, modals, formatting pipes. Imported by every feature module that needs them.

  • Why split — clear ownership: Core = app-wide singletons; Shared = reusable presentational pieces.

  • Don't put services in Shared — each importer gets its own instance; defeats singleton intent.

  • Modern alternative — standalone components + providedIn: "root" services; Core/Shared boilerplate fades.

// CoreModule — singletons, imported once by AppModule
@NgModule({
  declarations: [HeaderComponent, FooterComponent],
  imports: [CommonModule, HttpClientModule, RouterModule],
  providers: [
    AuthService,
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
  ],
  exports: [HeaderComponent, FooterComponent]
})
export class CoreModule {
  constructor(@Optional() @SkipSelf() parent?: CoreModule) {
    if (parent) {
      throw new Error('CoreModule is already loaded. Import it in AppModule only.');
    }
  }
}

// SharedModule — reusables, imported by many feature modules
@NgModule({
  declarations: [ButtonComponent, ModalComponent, CurrencyPipe],
  imports: [CommonModule, FormsModule],
  exports: [
    CommonModule,        // re-export so consumers don't have to import again
    FormsModule,
    ButtonComponent,
    ModalComponent,
    CurrencyPipe
  ]
})
export class SharedModule {}

CoreModule holds singletons — services and app-shell components that should exist exactly once. The constructor @Optional() @SkipSelf() guard throws if any module other than AppModule tries to import it, preventing lazy-loaded feature modules from creating duplicate AuthService instances. SharedModule holds reusables imported by many feature modules — buttons, modals, formatting pipes. Re-exporting CommonModule and FormsModule saves every consumer from importing them separately. With standalone components and providedIn: 'root', both patterns are less necessary in 2026 — but they're still very common in 2018-2022-era codebases you'll inherit.

Core = singletons imported once (auth, interceptors); Shared = reusables imported everywhere (buttons, pipes). @SkipSelf() import guard blocks double-instantiation.

Less relevant with providedIn: 'root'.

What are Core and Shared modules, and when do you use them? | Hiprup