Alex Rickabaugh & Mark Techson
[Alex] I came on board with the Angular team back in 2015, roughly around the Angular 2.0 launch. One of the earliest things I worked on was moving source code from JavaScript over to a then-newer language out of Microsoft called TypeScript. That language went on to become both an industry norm and one of the pillars of Angular, giving the team the structure and safety needed to scale the framework. We built Angular’s ahead-of-time compiler on top of the TypeScript compiler’s APIs. Compiling web apps wasn’t novel at Google, but it was uncommon across the broader web ecosystem at that point.
Jump to the present: TypeScript has carried Angular to some of the biggest web applications anywhere. The tooling landscape has shifted a lot over the past decade too. Lately there’s been a clear push toward writing higher-performance JavaScript compilers, bundlers, and other tooling in native code. TypeScript 7 shows just how far that approach can go, and we want to congratulate the TypeScript team on shipping a stable release and on the performance it brings. If you haven’t read their blog post, it’s worth a look, particularly the performance figures.
Angular’s compiler has one of the deepest TypeScript integrations in the web ecosystem, and we’ve long understood that this depth of integration can’t function against a Go-compiled TypeScript. Beyond the cost of crossing the language boundary, the Angular compiler carries out its own code transformations through the ts.Transformer API, which isn’t accessible across languages. Delivering the same native-tooling and TypeScript 7 gains to Angular developers means thinking differently. Early this year we began assembling a plan: separate Angular compilation from TypeScript’s compiler APIs, and create a new Angular-specific compiler that handles components, directives, and so on, emitting transformed TypeScript that any build pipeline or other compilation tool can consume. This path is well established; plenty of other web frameworks have likewise decoupled code generation from type-checking. Many of them also rely on the same library for those transformations: oxc.
Oxc, the Oxidation Compiler, is a native JavaScript parsing and compilation toolchain built by Void Zero. It’s written in Rust and exposes a stable, mature API for parsing, AST visitation, semantic analysis, and code transformation. Oxc is the engine behind their widely used Vite build tool. So, cliche as it may sound… we’re rewriting the Angular compiler in Rust 🦀 (in part).
At least while in development, we call the new tool the Angular Preprocessor (ngp), to set it apart from the existing TypeScript-based compiler (ngc). Here’s a high-level view of what it looks like:
Behind the scenes
ngp has two primary jobs: compile Angular decorators (@Component, @Pipe, etc) together with any related templates so they render efficiently at runtime, and enable the TypeScript compiler to type-check expressions inside component templates. For each input source file (say dashboard.ts) in your project, ngp emits two output files, one per job:
- A dashboard.ng.ts file holding your code, but with the Angular decorators swapped for their compiled equivalents. That file can go straight into TypeScript or directly into a bundler such as esbuild. This is the component code that gets loaded and run in the browser.
- A dashboard.ngtypecheck.ts file containing a translation of the expressions and types found in any component templates, which lets TypeScript type-check them and produce high-quality diagnostics.
Source maps are produced for both files, so downstream tools (TypeScript included) can report errors against your original input file.

For performance, these output files are typically created only in memory rather than written to disk.
The Hybrid Architecture
Eventually we want to move the whole compilation chain into native Rust code, but Angular has a sophisticated template compilation pipeline written in TypeScript, and rewriting it would take additional time. So ngp takes a hybrid route: Rust for the compiler’s frontend, TypeScript for the backend.
The frontend is a Rust library we call the analyzer. Built on oxc, it parses your code, locates Angular-decorated classes, maps how NgModules relate to their components and directives, pulls dependency information out of Angular Package Format libraries, and generates a list of compilation tasks. Since Rust and Oxc support multithreading well, the analyzer reads your source in parallel and streams compilation work units to the backend.
The backend is what carries out those tasks, calling Angular’s existing template compiler to produce output TypeScript, whether for runtime or for type-checking. It takes compilation tasks from the analyzer, generates code, and writes out the output files along with their sourcemaps. The ngp backend is TypeScript.
We rely on a tool called napi-rs, which packages Rust libraries as native plugins for node applications, or alternatively as WebAssembly bundles. With napi-rs, when ngp loads the analyzer it can either pull in a native library if one exists for your architecture and platform, or fall back to a WASM bundle. Supporting WASM also means the Rust analyzer can be loaded in browser environments, which helps online coding tools that need to compile Angular in a browser.
Current Status
ngp is approaching MVP status as a compiler. We’re running it against Google’s large collection of Angular applications to refine its correctness. We’re also prototyping integration into the CLI’s build system, and we have a prototype of the language service integration. Our goal is to ship an experimental version you can try in your own projects later this year. In the meantime, tell us what questions you have about this new compiler.
FAQ
Is the new compiler faster? Does it get the same 10x speedup as TypeScript 7?
It’s still too early to tell. TypeScript compilation accounts for only part of the overall type-checking, transpilation, minification, and bundling process. We’ll hold off on conclusions until we can benchmark the full build with the Angular CLI in a true apples-to-apples comparison, though some ad-hoc testing we’ve done looks encouraging.
What about the language service?
The new ngp engine can power the Angular language service too, and we have a working prototype of that integration.
Are there going to be breaking changes?
We’re testing the new compiler across Google’s entire Angular codebase and fixing any compatibility issues as we find them. That said, there are a few edge cases we know of where type checking behaves slightly differently with the new output, in ways that could surface new type errors. These have been extremely rare, but we’ll document them as breaking changes to be thorough. TypeScript 7 itself has several differences of this kind.
Why not use TypeScript’s interop APIs to port the existing compiler?
We plan to use TS 7.1 interop APIs for type-checking and diagnostics as part of our solution. We’ve worked closely with the TypeScript team at Microsoft to make sure TS 7.1’s APIs cover our use cases, and we’re grateful for their collaboration.
We did consider using the interop API layer for the entire compiler pipeline, but ruled it out for performance reasons. Angular’s compiler walks and processes the AST far more extensively than other consumers, and both we and the TypeScript team felt the gains from native processing were too significant to pass up.
Why not Go, like Microsoft chose?
The TypeScript team has done a great job documenting why they picked Go. Mostly it comes down to Go fitting much more naturally when porting a complex codebase from another garbage collected language. That wasn’t really a constraint for Angular, since our compiler manages more straightforward data structures. What decided it for us instead was having access to a high-quality, well maintained JavaScript/TypeScript toolchain: a library with a parser, AST, semantic binder, and code transformer. Where that requirement met our wish to work in native code is what led us to oxc and Rust.
Note: TypeScript 7 is itself a TypeScript parsing and transformation toolchain written in Go, though its APIs are private by design (at least in the initial release). Right now there’s no public library implementing a TypeScript parser and AST in Go.
Didn’t VoidZero already build an Angular compiler in Rust/oxc?
Yes! With some caveats, though. oxc-angular-compiler concentrates on Angular source transpilation (the compiler’s first task), but it doesn’t implement template type-checking (the second task) or the cross-file optimizations needed to keep non-standalone application bundles small. We need both of those capabilities.
Over the longer term, we’re interested in adapting oxc-angular-compiler’s port of our template parsing and compilation engine to shift more of ngp’s work into Rust.
An update on Angular’s TypeScript 7-powered Compiler was originally published in Angular Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.
