In this article, we’ll deep-dive into every line of a real-world app.config.ts file that integrates:
- Angular Standalone APIs
- PrimeNG theming (Lara theme)
- NgRx Store + Effects + DevTools
- HTTP Client with Fetch
- Markdown rendering (ngx-markdown + PrismJS highlighting)
- Zone optimization for better performance
By the end, you’ll understand how to structure, configure, and optimize your Angular 19 standalone app configuration file like a pro.
The Complete app.config.ts Code
Here’s the full configuration we’ll be dissecting:
import { ApplicationConfig, provideZoneChangeDetection, SecurityContext, isDevMode } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
import { providePrimeNG } from 'primeng/config';
import Lara from '@primeng/themes/lara';
import { routes } from './app.routes';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { CLIPBOARD_OPTIONS, ClipboardButtonComponent, MARKED_OPTIONS, MERMAID_OPTIONS, provideMarkdown } from 'ngx-markdown';
import 'prismjs';
import 'prismjs/components/prism-typescript.min.js';
import 'prismjs/plugins/line-numbers/prism-line-numbers.js';
import 'prismjs/plugins/line-highlight/prism-line-highlight.js';
import { provideStore } from '@ngrx/store';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { provideEffects } from '@ngrx/effects';
import { getModalsReducer } from './store/reducers';
import { Effects } from './store/effects';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideAnimationsAsync(),
providePrimeNG({
theme: {
preset: Lara,
options: {
// prefix: 'p',
darkModeSelector: 'false',
// colorScheme: 'light',
cssLayer: false
}
}
}),
provideHttpClient(withFetch()),
provideMarkdown({
mermaidOptions: {
provide: MERMAID_OPTIONS,
useValue: {
darkMode: true,
look: 'handDrawn',
},
},
clipboardOptions: {
provide: CLIPBOARD_OPTIONS,
useValue: {
buttonComponent: ClipboardButtonComponent,
},
},
sanitize: SecurityContext.NONE,
markedOptions: {
provide: MARKED_OPTIONS,
useValue: {
gfm: true,
breaks: false,
pedantic: false,
}
},
}),
provideStore({ modals: getModalsReducer }),
provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() }),
provideEffects([Effects])
]
};
What is app.config.ts in Angular 19?
In Angular 19 standalone apps, you don’t use AppModule anymore. Instead, you configure all global providers in one place — app.config.ts.
This configuration object (ApplicationConfig) is passed to your app’s entry point:
bootstrapApplication(AppComponent, appConfig);
It defines everything your app needs globally: routing, HTTP, theming, markdown, animations, NgRx, and more.
Line-by-Line Explanation
Let’s break it down step by step:
Core Angular Imports
import { ApplicationConfig, provideZoneChangeDetection, SecurityContext, isDevMode } from '@angular/core';
- ApplicationConfig — Type that defines app-wide providers for standalone apps.
- provideZoneChangeDetection — Configures Angular’s zone-based change detection.
- SecurityContext — Controls how Angular sanitizes content (used in Markdown rendering).
- isDevMode() — Detects if the app is running in development mode — handy for enabling debug tools conditionally.
Angular Router
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
- provideRouter(routes) installs Angular Router without needing RouterModule.forRoot().
- Your route definitions live in app.routes.ts, typically as a Routes array.
Animations Setup
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
- Enables Angular’s animation engine asynchronously.
- The async variant helps tree-shake animation code and reduce bundle size when animations aren’t immediately needed.
PrimeNG Theme Configuration
import { providePrimeNG } from 'primeng/config';
import Lara from '@primeng/themes/lara';
Then configured like this:
providePrimeNG({
theme: {
preset: Lara,
options: {
darkModeSelector: 'false',
cssLayer: false
}
}
})
- providePrimeNG() globally sets up PrimeNG.
- preset: Lara applies the beautiful Lara theme.
- darkModeSelector — defines a CSS selector for dark mode (here it’s disabled).
- cssLayer — controls CSS layering behavior. Setting it false prevents layering issues if you manage your own global styles.
You can customize prefix, color scheme, or even dynamically switch themes later.
HTTP Client with Fetch API
import { provideHttpClient, withFetch } from '@angular/common/http';
- provideHttpClient() — Bootstraps the modern Angular HTTP Client for standalone apps.
- withFetch() — Uses the native Fetch API under the hood (instead of XMLHttpRequest).
Benefits:
- Smaller bundle size
- Modern streaming support
- Better Service Worker integration
If your app relies on progress events, verify behavior as Fetch doesn’t provide them the same way as XHR.
Markdown Rendering with ngx-markdown
import { CLIPBOARD_OPTIONS, ClipboardButtonComponent, MARKED_OPTIONS, MERMAID_OPTIONS, provideMarkdown } from 'ngx-markdown';
Then configured as:
provideMarkdown({
mermaidOptions: {
provide: MERMAID_OPTIONS,
useValue: {
darkMode: true,
look: 'handDrawn',
},
},
clipboardOptions: {
provide: CLIPBOARD_OPTIONS,
useValue: {
buttonComponent: ClipboardButtonComponent,
},
},
sanitize: SecurityContext.NONE,
markedOptions: {
provide: MARKED_OPTIONS,
useValue: {
gfm: true,
breaks: false,
pedantic: false,
}
},
})
This setup enables:
- Markdown rendering via the marked library.
- Mermaid diagrams (MERMAID_OPTIONS) with dark mode and hand-drawn style.
- Clipboard copy button (ClipboardButtonComponent) for code snippets.
- sanitize: SecurityContext.NONE — disables sanitization, allowing raw HTML in Markdown.
Security Tip:
Only set SecurityContext.NONE if the Markdown content is 100% trusted. Otherwise, use SecurityContext.HTML to avoid XSS risks.
Syntax Highlighting with PrismJS
import 'prismjs';
import 'prismjs/components/prism-typescript.min.js';
import 'prismjs/plugins/line-numbers/prism-line-numbers.js';
import 'prismjs/plugins/line-highlight/prism-line-highlight.js';
- These are side-effect imports.
- They load PrismJS with TypeScript syntax highlighting and plugins for line numbers and line highlighting.
- Perfect for rendering code blocks in documentation or Markdown.
You can add more languages by importing other Prism components.
State Management with NgRx
import { provideStore } from '@ngrx/store';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { provideEffects } from '@ngrx/effects';
import { getModalsReducer } from './store/reducers';
import { Effects } from './store/effects';
Configured as:
provideStore({ modals: getModalsReducer }),
provideStoreDevtools({ maxAge: 25, logOnly: !isDevMode() }),
provideEffects([Effects])
Explanation:
- provideStore() — Registers your global store with a reducer map.
- modals: getModalsReducer — Example slice managing modal dialogs.
- provideStoreDevtools() — Enables Redux DevTools integration (logs up to 25 states).
- logOnly: !isDevMode() — Prevents dispatching actions from DevTools in production.
- provideEffects() — Registers side effects for async logic (API calls, etc.).
Bonus: Zone Optimization
provideZoneChangeDetection({ eventCoalescing: true })
- eventCoalescing: true batches multiple synchronous DOM events to reduce unnecessary change detection cycles.
- Results in better performance for interactive UIs (forms, scroll events, etc.).
Putting It All Together
This single file replaces what used to be spread across multiple NgModules, AppModules, and providers.
Here’s how it connects to your main.ts:
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { appConfig } from './app.config';
bootstrapApplication(AppComponent, appConfig)
.catch(err => console.error(err));
And just like that — your Angular 19 standalone app is ready with routing, theming, Markdown rendering, Prism highlighting, and NgRx state management — all bootstrapped from a single file.
Best Practices & Recommendations
- Avoid SecurityContext.NONE unless Markdown is from a trusted source.
- Conditionally enable Store DevTools only in dev mode for smaller bundles.
- Lazy-load PrismJS if bundle size matters.
- Verify darkModeSelector — ensure it’s boolean or valid CSS selector per PrimeNG docs.
- Split providers logically (UI, State, Markdown) for easier maintenance.
Summary
The app.config.ts in Angular 19 is the heart of your standalone app.
It centralizes:
- Routing (provideRouter)
- Animations (provideAnimationsAsync)
- PrimeNG theming (providePrimeNG)
- HTTP Client (provideHttpClient(withFetch))
- Markdown rendering (provideMarkdown)
- Syntax highlighting (PrismJS)
- State management (NgRx)
This approach is cleaner, faster, and easier to maintain — fully embracing the new Angular standalone paradigm.
Final Thoughts
With this setup, you’re not just configuring an app — you’re modernizing your Angular architecture for the standalone era.
If you found this breakdown helpful, consider ❤️ reacting and bookmarking it on Dev.to — it helps others discover this guide too!
Top comments (0)