VS Code is the default Angular editor for good reason: the Angular Language Service makes templates type-safe, the integrated terminal runs the CLI, and the built-in debugger steps through your TypeScript in the browser. This guide takes you from an empty editor to a running, debuggable Angular 22 app — the workflow, the extensions that matter, and the configuration that makes VS Code feel purpose-built for Angular. Every command and number below is real, captured from the companion repository.

From zero to a running app
With the environment set up — Node 24 via a version manager and the Angular CLI — the whole loop lives in VS Code's integrated terminal (Ctrl+`):
ng new my-app --style css
code my-app # open the workspace
ng serve
http://localhost:4200 hot-reloads on every save. Keep ng serve running in one terminal tab permanently and open a second tab for ng generate commands — VS Code's split terminal (Ctrl+Shift+5) shows both at once.
The part of the workspace you actually touch day to day:
src/
├── app/
│ ├── app.ts root component (class)
│ ├── app.html its template
│ ├── app.config.ts application providers
│ └── app.routes.ts routes
├── main.ts bootstrap
└── styles.css global styles
Two things surprise people coming back to Angular after a few years. Files are named app.ts, not app.component.ts, and there are no NgModules anywhere — standalone components are the default. If a tutorial opens app.module.ts, it predates the current model by several major versions.
The loop, and where each tool fits

Every one of those steps happens without leaving the editor, and the round trip is under a second on a small app. What makes it fast is the build pipeline — esbuild under @angular/build — and what makes it safe is the Language Service checking your templates as you type.
The Angular Language Service changes everything
Install the Angular Language Service (angular.ng-template) first. It is the difference between editing templates as strings and editing them as code:
- Autocomplete inside HTML for component properties, inputs, and pipes.
- Red squiggles in templates for typos —
{{ prodcut.name }}becomes an error while you type, instead of a blank spot on the page at runtime. - F12 go-to-definition from a template expression into the TypeScript class, and from a component tag into its definition.
- Hover types in templates, so you can see that
product()really is aProduct.
Pair it with strict template checking in tsconfig.json so CI enforces exactly what the editor shows you:
{
"compilerOptions": { "strict": true },
"angularCompilerOptions": {
"strictTemplates": true,
"typeCheckHostBindings": true
}
}
Two more extensions earn their place: Prettier for formatting and EditorConfig so indentation and line endings survive contact with other editors. Commit your picks in .vscode/extensions.json and new teammates get prompted automatically:
{
"recommendations": [
"angular.ng-template",
"esbenp.prettier-vscode",
"editorconfig.editorconfig"
]
}
Generating code without leaving the editor
The CLI scaffolds; VS Code makes it fluent:
ng generate component product-list
ng generate service cart
ng generate directive highlight
Each command produces the class, template, styles, and a spec file, wired with current defaults. There's a right-click "Generate Component" in Angular's own extension pack if you prefer clicking, but most developers end up faster in the terminal.
The genuinely underrated feature here is auto-import. When you use <app-product-card /> in a template, VS Code's lightbulb offers to add ProductCard to your component's imports array — the step everyone forgets when doing it by hand, and the source of the "component renders as nothing" confusion.
Debugging: real breakpoints in TypeScript
No extension needed — VS Code's built-in JavaScript debugger attaches to Chrome or Edge. Create .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "ng serve",
"type": "chrome",
"request": "launch",
"preLaunchTask": "npm: start",
"url": "http://localhost:4200/"
}
]
}
With ng serve running, F5 launches the browser and your breakpoints in .ts files bind through source maps. You step through component code, inspect a signal's current value, and watch input() values change as you interact — considerably faster than console.log archaeology.
One caveat worth knowing if you copy a launch.json from an older project: Angular's test runner is now Vitest, not Karma, and it runs in Node rather than a browser. An inherited "ng test" configuration pointing at http://localhost:9876/debug.html targets a server that no longer exists. The current shape is a Node launch:
{
"name": "ng test",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/@angular/cli/bin/ng.js",
"args": ["test"],
"console": "integratedTerminal"
}
For quick inspection without the debugger, the Angular DevTools browser extension shows the component tree and profiles change detection.
Tasks, tests, and the rest of the loop
- Tests:
ng testruns Vitest. In the companion repo the whole suite finishes in well under a second:
Test Files 1 passed (1)
Tests 2 passed (2)
Duration 522ms
- Problems panel (
Ctrl+Shift+M) aggregates TypeScript and template errors across the project. After a big rename, it's your to-do list. - Format on save with Prettier keeps diffs about behaviour rather than whitespace.
- Tasks: the scaffold's
tasks.jsonmarksnpm: startas a background task with begin/end patterns so VS Code knows when a rebuild finishes.npm: testshould not be a background task now that Vitest runs to completion — a stale background matcher there just hangs waiting for output that never comes.
The shortcuts that actually pay for themselves
Angular projects are wide — dozens of small files rather than a few large ones — so navigation speed matters more than in most stacks:
| Shortcut | What it does | Why it matters in Angular |
|---|---|---|
Ctrl/Cmd + P |
Fuzzy file open | Type prod-card and land on product-card.ts without touching the tree |
Ctrl/Cmd + T |
Symbol search across the project | Jump straight to a component class or service by name |
F12 / Alt + F12 |
Go to / peek definition | Works from inside a template thanks to the Language Service |
Shift + F12 |
Find all references | Before renaming an input(), see every parent binding to it |
F2 |
Rename symbol | Renames the class and its usages together, templates included |
Ctrl/Cmd + . |
Quick fix | The auto-import lightbulb for standalone imports |
F2 deserves special mention. Renaming a component the manual way means touching the class, the selector, the file name, and every template that uses it. With strict templates on and the Language Service running, a rename that misses something turns into a build error rather than a silently blank section of page.
Working across two projects at once
Real work often means an Angular app in one folder and its API in another. Rather than juggling two windows, save a multi-root workspace — File → Add Folder to Workspace, then Save Workspace As — and you get one search index, one Problems panel, and one set of terminals across both. The .code-workspace file is small and worth committing:
{
"folders": [{ "path": "web" }, { "path": "api" }],
"settings": { "editor.formatOnSave": true }
}
A second habit worth forming: keep ng serve in a terminal that you never close, and use the terminal dropdown to name tabs (serve, test, git). Angular's dev server prints its rebuild timings, so a tab that suddenly reports a two-second rebuild is telling you something about what you just imported.
A five-minute first component
The full loop, editor to browser:
ng generate component hello
// src/app/hello/hello.ts
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-hello',
template: `
<h2>Hello {{ name() }}</h2>
<input #box (input)="name.set(box.value)" placeholder="Your name" />
`,
})
export class Hello {
readonly name = signal('Angular');
}
Add <app-hello /> to app.html, accept the auto-import, and save. The browser updates as you type into the input — a signal driving the view with no ceremony, no subscription, and no change-detection strategy to configure.
That tight save-and-see loop, with types checked all the way into your HTML, is the actual reason this stack is pleasant to work in.
Where to go next
With the editor set up, the framework itself is next. The components tutorial builds real components with signals on this workspace, directives covers the @if/@for template syntax, nested components wires parents to children, and lifecycle hooks explains what runs when.
Everything in this series lives in one runnable workspace — clone the companion repository, run npm install && npm start, and read along with the code open beside you.
Comments (0)
No comments yet — be the first to share your thoughts.