Setting up a workspace with the Angular CLI
Create a workspace with the options that matter, understand the files the CLI generates, and know where configuration actually lives.
ng new and the options that matter
npm install -g @angular/cli
ng version
ng new billing-portal \
--style=css \
--ssr=false \
--zoneless \
--routing \
--package-manager=pnpm \
--skip-git=false
cd billing-portal
ng serve --open
ng build --configuration production| Flag | Effect | Why it matters |
|---|---|---|
--style | Chooses the stylesheet language | Hard to change later; the component metadata references the extension |
--ssr | Adds a server entry point and hydration | Adds complexity; enable it when you need rendering or SEO |
--zoneless | Omits Zone.js and enables signal-based change detection | Smaller bundle, better performance, but every async update must notify explicitly |
--routing | Generates app.routes.ts | You can add routing later, but starting with it avoids a refactor |
--standalone | Components declare their own imports | The default in modern Angular; NgModules are now optional |
--skip-tests | No spec files | Only sensible when the project genuinely will not be tested |
💡
Zoneless is a commitment rather than a toggle. Anything that updates state from outside Angular — a
setTimeout, a WebSocket callback, a third-party library — must touch a signal or call markForCheck. Decide before you write the first component.What the CLI generates
billing-portal/
angular.json build, serve and test targets per project
package.json dependencies and npm scripts
tsconfig.json base TypeScript config, strict by default
tsconfig.app.json app-specific compiler options
src/
main.ts bootstrapApplication(AppComponent, appConfig)
app/
app.ts the root standalone component
app.config.ts providers: router, http, etc.
app.routes.ts the route table
app.html / app.css
index.html
styles.css
public/ copied verbatim into the build output// src/app/app.config.ts — the composition root
import { ApplicationConfig, provideBrowserGlobalErrorListeners,
provideZonelessChangeDetection } from '@angular/core';
import { provideRouter, withComponentInputBinding, withViewTransitions } from '@angular/router';
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { authInterceptor } from './core/auth.interceptor';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideZonelessChangeDetection(),
provideRouter(routes, withComponentInputBinding(), withViewTransitions()),
provideHttpClient(withFetch(), withInterceptors([authInterceptor]))
]
};main.tsshould stay three lines: it bootstraps the root component with the app config and nothing else.- Testing and build settings live per project in
angular.json; there is no hidden webpack file to edit and nong eject. - The new build system is esbuild-based, so builds are dramatically faster but the output is not a webpack bundle — anything that patched webpack internals will not carry over.
public/is copied as-is and referenced from the site root, which is where favicons androbots.txtbelong.
ng generate and budgets
ng generate component invoices/invoice-list
ng g c shared/ui/stat-card --change-detection=OnPush --skip-tests
ng g s core/auth
ng g guard core/require-auth # a functional CanActivateFn
ng g interceptor core/auth
ng g environment
ng g c invoices/invoice-list --dry-run # print the plan, write nothing
ng config schematics.@schematics/angular:component.changeDetection OnPush
ng config cli.analytics false// angular.json — budgets are the mechanism that keeps a bundle from creeping
{
"configurations": {
"production": {
"budgets": [
{ "type": "initial", "maximumWarning": "400kB", "maximumError": "600kB" },
{ "type": "anyComponentStyle", "maximumWarning": "4kB", "maximumError": "8kB" },
{ "type": "bundle", "name": "vendor", "maximumWarning": "200kB" }
],
"outputHashing": "all",
"optimization": true,
"sourceMap": false
},
"development": {
"budgets": [
{ "type": "initial", "maximumWarning": "2MB", "maximumError": "4MB" }
]
}
}
}| Command | Use it for | Note |
|---|---|---|
ng serve | Local development | Hot module replacement is on by default |
ng build | Deployment artefact | Add --configuration production for a real build |
ng build --stats-json | Bundle analysis | Feed stats.json to a bundle visualiser |
ng test | Unit tests | Runner and builder are configurable |
ng extract-i18n | Translation catalogues | Outputs XLIFF or JSON |
ng update | Framework upgrades | Runs migrations; commit first |
Set strict in tsconfig.json on day one. Turning on strictTemplates later is a large refactor, and it is the check that catches the majority of real template bugs — a mistyped property or a wrong event payload.
FAQ
Standalone or NgModules?
Standalone. It is the default for new work, requires less ceremony, and makes dependencies explicit at the point of use. NgModule-based code still compiles, so an existing application can migrate one component at a time.
Should I enable server-side rendering from the start?
Only if you need it — search indexing of public pages, or a measurable first-contentful-paint problem on slow networks. SSR changes how you write code: no direct
window access on the server, and every request must be careful about shared state.Related
Components and templates Server rendering, hydration and deployment
Last refreshed 2026-09-18.