Angular Package Format (APF): The Backbone of Angular Libraries
When building Angular libraries, you want your package to "just work" for everyone—across different projects, build tools, and Angular versions. The Angular Package Format (APF) is the official standard that makes this possible.
Why Does APF Exist?
Angular is more than a framework—it's an ecosystem. Libraries are everywhere: UI kits, utilities, data layers, and more. But not all npm packages are created equal! Without a standard, library consumers would face:
- Build errors or warnings
- Broken type definitions
- Incompatibility with Angular CLI or Ivy
- Tree-shaking issues (unused code in bundles)
APF solves these problems by defining how Angular libraries should be structured, built, and published.
A Brief History of APF
Angular libraries have evolved alongside the framework itself. Here's a quick timeline:
- Angular 2–5: Early libraries shipped multiple formats (ES5, UMD, ESM) and special metadata for View Engine. No formal spec.
- Angular 6 (2018): APF v6 introduced. ES modules by default,
sideEffects: falsefor tree-shaking, and better CLI support. - Angular 8: TypeScript types are bundled per entry point. Deep imports discouraged.
- Angular 10:
tslibrequired as a dependency for helper functions. - Angular 13: Major simplification—no more View Engine, only Ivy. Legacy formats (CommonJS, UMD) removed. ES2020 is the new baseline.
- Angular 16: Packages target ES2022. Even leaner, faster, and more future-proof.
Anatomy of an APF Package
A typical APF-compliant package looks like this:
my-angular-lib/
├── README.md
├── package.json
├── index.d.ts
├── fesm2022/
│ └── my-angular-lib.mjs
└── ...Key elements:
package.json: The heart of your package. Includes special fields:type: "module"(ESM by default)sideEffects: false(enables tree-shaking)exports(controls public entry points)peerDependencies(e.g.,@angular/core,tslib)
index.d.ts: Bundled TypeScript types for your public API.fesm2022/: Flattened ES2022 module (main entry point for consumers).- Secondary entry points (optional): e.g.,
my-angular-lib/testingfor test utilities ormy-angular-lib/buttonfor a button component.
Deep Dive: package.json Fields
A well-formed package.json is crucial for APF. Here are the most important fields:
{
"name": "my-angular-lib",
"type": "module",
"sideEffects": false,
"exports": {
".": {
"types": "./index.d.ts",
"esm2022": "./fesm2022/my-angular-lib.mjs"
},
"./testing": {
"types": "./testing/index.d.ts",
"esm2022": "./fesm2022/my-angular-lib-testing.mjs"
}
},
"peerDependencies": {
"@angular/core": ">=16.0.0",
"tslib": ">=2.0.0"
}
}exports: Controls what consumers can import. Prevents deep imports into internal files.sideEffects: false: Tells bundlers your code has no global side effects, enabling tree-shaking.peerDependencies: Ensures consumers use compatible Angular and tslib versions.
How APF Enables Tree-Shaking
Tree-shaking is the process of removing unused code from your final bundle. APF helps by:
- Using ES modules (static imports/exports)
- Marking the package as
sideEffects: false - Bundling all public APIs in a single entry point
This means consumers only get the code they actually use—no more, no less.
Building an APF-Compliant Library
The easiest way is to use Angular CLI and ng-packagr (or Nx):
ng generate library my-lib
ng build my-libThe both tools will generate an APF-compliant package and we already did it in the previous lesson.
Secondary Entry Points
Large libraries often split features into sub-packages (e.g., @angular/material/button). APF supports this via secondary entry points:
- Each entry point gets its own folder,
package.json, and type definitions. - The main
exportsfield in the rootpackage.jsonmaps these entry points.
Example:
"exports": {
".": { ... },
"./button": {
"types": "./button/index.d.ts",
"esm2022": "./fesm2022/my-angular-lib-button.mjs"
}
}This lets consumers import only what they need:
import { MyButtonComponent } from 'my-angular-lib/button';We will use secondary entry points in the next lesson!
Common Pitfalls & Best Practices
- Don't use deep imports (e.g.,
my-lib/esm2022/foo). Always import from the public API. - Keep dependencies up to date: Especially
tsliband Angular peer dependencies. - Test your package: Try installing it in a fresh Angular project before publishing.
- Document your entry points: Make it clear in your README how to import features.
And allways use the ng-packagr to build your library! It will generate an APF-compliant package for you. ng-packagr is the only tool that fully supports APF!
The Future of APF
APF evolves with Angular. As the framework targets newer JavaScript versions and build tools, APF will continue to simplify and modernize. Staying up to date with Angular CLI and its generators is the best way to ensure your library remains compatible.
More Than Just APF: What ng-packagr Brings to the Table
While ng-packagr's main job is to implement the Angular Package Format (APF), it also provides a rich set of features that make building and publishing Angular libraries much easier and more robust.
Here's a quick overview of what it offers out of the box:
Packaging & Compatibility
- 🎁 Implements Angular Package Format
- 🏁 Produces optimized FESM2022 bundles
- 🧳 Packages are ready for Angular CLI, Webpack, and ESM bundlers
- 💃 Generates TypeScript definitions (
.d.ts) - 🔎 Supports both scoped and non-scoped npm packages
Assets & Styles
- 🏄 Inlines component templates and stylesheets
- ✨ Advanced CSS support:
- 🐫 SCSS preprocessing with custom include paths
- 🐒 Automatic vendor prefixing
- 🐯 Embeds asset data directly into your bundle
Read also
- Why an Angular Course Platform Runs on Next.js
- Why you need Angular
- Angular 20: stable Signals, Zoneless and more
🎁 Pre-order now — "Angular UI Kit"
We’re launching our first interactive course on ng.guide, where you'll build a production-grade UI library using real-world Angular practices.
- Fully interactive lessons
- Real components and examples
- One-click Stackblitz integration
💸 What it costs today — including whatever offer is running, quoted from the catalogue the checkout charges from.
Reserve your access now and get hands-on with how Angular works at scale.
