All articles

Angular in Visual Studio Code

The editor setup that makes Angular pleasant: Language Service, auto-imports, real breakpoints, and the Vitest-era launch config.

0 · log in to like, save & follow Share on LinkedIn Share on X

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.

Angular in Visual Studio Code

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

The VS Code and Angular development loop

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 a Product.

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 test runs 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.json marks npm: start as a background task with begin/end patterns so VS Code knows when a rebuild finishes. npm: test should 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.

Enjoyed this article? Get the best GeeksArray articles in your inbox — once a week, no spam, unsubscribe anytime.

Comments (0)

Log in to join the conversation.

No comments yet — be the first to share your thoughts.