skip to content

In Angular, how do developer preview and experimental APIs differ from stable ones, and would you ship them to production?

level: middleimportance: nice to knowfreq 28%

answer

  1. outside semver guarantees
  2. polished vs may never stabilise
  3. can change in a patch
  4. JSDoc stability tags in source

basics

~20 s

Developer preview APIs in Angular are complete and polished but not yet stabilised; experimental APIs may change heavily or never stabilise. Neither is covered by semver or the deprecation policy, so either can change even in a patch release.

solid answer

~40 s

Stable Angular APIs follow semantic versioning and the deprecation policy. **Developer preview** APIs are fully functional and polished, but the team is not ready to stabilise them, usually to gather feedback or because docs or migration tooling are incomplete. **Experimental** APIs might change significantly or never become stable. For both, the versioning and deprecation policies **do not apply**: they can change at any time, even in a patch. In the source they carry tags such as `@developerPreview 20.0` or `@experimental 22.0`, while stable ones carry `@publicApi`. Using them in production is a team decision: developer preview is often reasonable if you wrap it, pin versions with a lockfile and read every changelog; experimental needs a stronger reason and an exit plan.

go deeper

for a junior

Remember that Angular labels some APIs developer preview or experimental, and that those labels mean the usual upgrade guarantees do not apply.

for a middle

Explain the difference: developer preview is polished but not yet stabilised, experimental may change heavily or never stabilise, and both can change in a patch.

for a senior

Describe the guard rails you would put around a developer preview API in production: wrappers, lockfile discipline, changelog reading and tests on its behaviour.

for a principal

Set a team rule for which stability levels may enter shared libraries versus leaf applications, and who approves exceptions.

Angular marks every public API with a stability level. The level decides which promises from the versioning policy you actually get when you depend on it. ## The three levels | Level | Source tag | What it promises | | :-- | :-- | :-- | | **Stable** | `@publicApi` (often with a version, e.g. `@publicApi 20.0`) | Semver and the deprecation policy: no breaking change outside a major, at least one major of deprecation before removal | | **Developer preview** | `@developerPreview` (e.g. `@developerPreview 20.0`) | Fully functional and polished, but not yet stabilised; may change at any time, even in a patch | | **Experimental** | `@experimental` (e.g. `@experimental 22.0`) | May change significantly before stabilising, or never stabilise at all | The docs give the reasons an API sits in **developer preview**: the team wants feedback from real applications before committing to it, or the documentation or migration tooling is not complete yet. Feedback goes through GitHub issues. **Experimental** is the earlier and riskier stage: the design itself may still move. ## Examples in v22.2 - The `@boundary` / `@error` template blocks for error boundaries are in **developer preview**, and the `ErrorDetails` interface they report is tagged `@developerPreview 22.2`. - `provideCheckNoChangesConfig()` is tagged `@developerPreview 20.0`. - Stability can be set **per member**: the `PendingTasks` class is `@publicApi 20.0`, while its `run()` method is still `@developerPreview 19.0`. - **Signal Forms** (`@angular/forms/signals`) were graduated to public API in 22.0, yet individual members there are still tagged `@experimental`. ## What "the policy does not apply" meant in practice The best-known cases are the signal APIs. **`effect()` changed its timing in v19 while it was in developer preview**: effects triggered outside change detection began running as part of change detection instead of as a microtask, and effects triggered during change detection began running before the component's template. Tests needed adjusting. Teams using it had accepted that risk. **`toSignal()`** only became stable API in v20 (it is tagged `@publicApi 20.0`), after several majors in which its behaviour could still change. The pattern is the usual path: 1. an API lands as **experimental** or **developer preview**; 2. real applications use it and report problems; 3. it is **stabilised** (the changelog says "mark ... as stable" or "graduate ... to public API"), and from then on semver and the deprecation policy protect it. ## Stabilisation is itself an upgrade event When an API graduates, its stable shape is not always its preview shape. The 20.0.0 changelog shows both outcomes: - `linkedSignal` was **stabilised** as it was; - `afterRender` was **renamed to `afterEveryRender` and stabilised** in the same change, so code using the preview name had to move. So when you plan an upgrade across a major, search the changelog for "stable", "stabilize" and "graduate" entries for every preview API you use: those are the places where your code may have to change even though no stable API was broken. ## Should production code use them? There is no blanket answer. The docs leave it to each team to decide whether the benefit is worth the risk of breaking changes. A reasonable policy: - **Developer preview: usually acceptable, with guard rails.** - Keep usage behind a small wrapper or a few call sites, so a changed signature is a local fix. - Rely on the lockfile, so even a patch update is a deliberate act. - Read the changelog for every update, patches included. - Cover the behaviour with tests that fail loudly if timing or semantics shift. - **Experimental: only with a concrete payoff and an exit plan.** Assume it may be redesigned or dropped; do not put it at the base of shared libraries that other teams depend on. - **Stable: the default.** When a stable alternative exists, prefer it. ## How to check an API's level 1. The guide for the feature says so up front; the error boundaries guide opens by stating that `@boundary` is in developer preview. 2. The JSDoc on each declaration carries the tag (`@publicApi`, `@developerPreview` or `@experimental`), usually with the version it was set in. 3. The changelog records the moment an API is marked stable, which is when the guarantees start. A candidate who says "it is in the official package, so it is covered by semver" has missed the point: being published and being stable are different things, and the tag decides which one you have.

  • Can an Angular developer preview API change in a patch release?
    Yes. The versioning and deprecation policies explicitly do not apply to developer preview APIs, so they may change at any time, including in a patch. That is why teams using them rely on the lockfile and read every changelog, not only those of majors.
  • Give an example of an Angular API that changed behaviour while in developer preview.
    effect() in v19: effects triggered outside change detection moved from running as a microtask to running as part of change detection, and effects triggered during change detection started running before the component's template. It was allowed because effect() was still developer preview; it became stable in v20.

saying these in an interview costs you the question

  • Everything exported from an @angular package is covered by semver.
  • Developer preview APIs cannot change until the next major release.
  • Experimental and developer preview mean the same thing in Angular.
  • An API that is still experimental is guaranteed to become stable later.
  • Developer preview APIs are unfinished and should never reach production.