How to Manage a Single Active Preview When Some Features Always Remain In Preview
For some Resource Providers, whenever a new stable version is released, a new preview version is created, because some preview features are not ready to be stable, but may become stable in a future version. To accommodate this need and account for the limitations of breaking change checks, which require a single version change for any PR into the rest-api-specs repo, the recommended solution is to introduce a stable and subsequent preview together in your TypeSpec api description and then split this change into two PRs: one representing the new stable and the second representing the subsequent preview. This involves the following steps described in the sections below:
- Create the new preview version based on the latest preview version
- Create the stable version (which should immediately precede the new preview version)
- Fill in examples for each
- Create a copy of the spec with just the stable release changes for your first PR
- After this PR is merged, create a PR with the whole spec, effectively adding the new preview
Creating New Preview and Stable Versions
Section titled “Creating New Preview and Stable Versions”-
If the existing preview version is
A, add the new stable versionA + 1and the new preview versionA + 2to the Versions enumeration, ensure that versionA + 2is decorated with@previewVersionfrom theAzure.Corelibrary (and remove that decoration from any other version). -
For all changes from preview version
Athat are part of stable versionA + 1, do the following:-
if a new type was added in
Aand is now stable (@added(T, A)), add the new decorator@added(T, A + 1)@added(Versions.`2025-10-01-preview`)@added(Versions.`2025-11-01`)remainType: string; -
if a type was made optional in
Aand this change is now stable (@madeOptional(T, A)), add the new decorator@madeOptional(T, A + 1)@madeOptional(Versions.`2025-10-01-preview`)@madeOptional(Versions.`2025-11-01`)optionalType?: string; -
if a type was renamed in
Aand this change is now stable (@renamedFrom(T, A, Name)), add the new decorator@renamedFrom(T, A + 1, Name)@renamedFrom(Versions.`2025-10-01-preview`, "oldName")@renamedFrom(Versions.`2025-11-01`, "oldName")newName: string; -
if a property or parameter had its type changed in
Aand is now stable (@typeChangedFrom(T, A, U)), add the new decorator@typeChangedFrom(T, A + 1, U)@typeChangedFrom(Versions.`2025-10-01-preview`, int32)@typeChangedFrom(Versions.`2025-11-01`, int32)changedType: string; -
if an operation returnType was changed in
Aand this change is now stable (@returnTypeChangedFrom(T, A, U)), add the new decorator@returnTypeChangedFrom(T, A + 1, U)@returnTypeChangedFrom(Versions.`2025-10-01-preview`, void)@returnTypeChangedFrom(Versions.`2025-11-01`, void)move is ArmResourceActionSync<Widget, MoveRequest, MoveResponse> -
If a type was removed in
Aand this change is now stable (@removed(T, A)), add the new decorator@removed(T, A + 1)@removed(Versions.`2025-10-01-preview`)@removed(Versions.`2025-11-01`)goneType: string;
-
-
Change all versioning decorators
dec(T, A, args)todec(T, A + 2, args)whereTis a type,Ais the latest preview version,A + 2is the new preview version you added in the first step andargsare any additional arguments to the decorator. Note that, after this change, some decorators will be duplicated in versionA + 1and versionA + 2. This is expected.@removed(Versions.`2025-10-01-preview`)@removed(Versions.`2025-11-01`)@removed(Versions.`2025-12-01-preview`)goneType: string;@renamedFrom(Versions.`2025-10-01-preview`, "oldName")@renamedFrom(Versions.`2025-12-01-preview`, "oldName")newName: int32; -
Add any new type changes to stable version (A + 1) and decorate appropriately, as shown in the versioning guide. Note that these changes should also appear in the new preview (A + 2)
-
Remove version
Afrom the versions enumerationenum Versions {@previewVersion`2025-10-01-preview`,`2025-11-01`,@previewVersion`2025-12-01-preview`,} -
Create examples directories for the new stable version (A + 1) and populate them with appropriate examples
-
If version A is not needed in the specs repo (see Should I delete an old preview if you are not sure)
-
Remove its example folder
Terminal window > rm -r examples/2025-10-01-preview -
Remove the OpenAPI spec for version A
-
Remove all references to version A in
README.md
-
Create A Copy of the Spec for the Stable Version only
Section titled “Create A Copy of the Spec for the Stable Version only”- Create a complete copy of your spec
- This copy will be used to contain just the new stable version (use this to create the first PR into the specs repo). Call this Copy.
- The original version will contain both the new stable and preview versions (use this to create the final PR after the first PR is merged). Call this Original.
- Do the following with the Copy
-
Remove all decorators that reference version
A + 2and use the same parameters as inA + 1- For example, if these decorators exist:
@added(T, A + 2) @added(T, A + 1), then, after this step, only@added(T, A + 1)should remain in this copy of the spec.
@added(Versions.`2025-11-01`)@added(Versions.`2025-12-01-preview`)addedType: string; - For example, if these decorators exist:
-
Undo and remove any remaining decorators referencing
A + 2using the following guide:-
For any type
Tdecorated with@added(T, A + 2), delete the typeTand all its decorators@added(Versions.`2025-12-01-preview`)goneType: string; -
For any type
Tdecorated with@removed(T, A + 2), remove the decorator@removed(Versions.`2025-12-01-preview`)remainType: string; -
For any type
Tdecorated with@renamedFrom(T, A + 2, oldName)rename the typeoldNameand remove the decorator@renamedFrom(Versions.`2025-12-01-preview`, "oldName")newName: string;oldName: string; -
For any property or parameter
Tdecorated with@typeChangedFrom(T, A + 2, oldType)set the type of the property tooldTypeand remove the decorator@typeChangedFrom(Versions.`2025-12-01-preview`, int32)changedType: string;changedType: int32; -
For any operation
Tdecorated with@returnTypeChangedFrom(T, A + 2, oldType)set the return type of the operation tooldTypeand remove the decorator@returnTypeChangedFrom(Versions.`2025-12-01-preview`, void)move is ArmResourceActionSync<Widget, MoveRequest, MoveResponse>;move is ArmResourceActionSync<Widget, MoveRequest, void>; -
For any property or parameter
Tdecorated with@madeOptional(T, A + 2)make the parameter or propertyTrequired and remove the decorator@madeOptional(Versions.`2025-12-01-preview`)remainType?: string;remainType: string;
-
-
Remove version
A + 2from the version enum.enum Versions {`2025-11-01`,@previewVersion`2025-12-01-preview`,} -
Compile the spec to produce artifacts (especially the new stable version (
A + 1) openapi ) -
Add the new stable version (
A + 1) to the README.md file. -
Create and merge the PR
-
Create a PR with the Combined Spec
Section titled “Create a PR with the Combined Spec”- Do the following with the Original
- Follow the instructions for normalizing decoration in the converting specifications document. This will remove any redundant decoration between the new stable and preview versions (
A + 1andA + 2). - Add any type changes that are introduced in the new preview and decorate appropriately, following the versioning guide
- Add a new example folder for the new preview version and populate with appropriate examples.
- Compile the spec to produce artifacts (especially the new stable and preview version (
A + 1andA + 2) apis). - Copy the README.md from copy 1 and add the new preview version to the file.
- Create and merge the final PR - this copy will be your specification going forward.
- Follow the instructions for normalizing decoration in the converting specifications document. This will remove any redundant decoration between the new stable and preview versions (