Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 253 additions & 0 deletions documentation/MIGRATION-guide-for-modularized-libraries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
# Guide for migrating to the modularized libraries of Azure JavaScript SDK
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Guide for migrating to the modularized libraries of Azure JavaScript SDK
# Guide for migrating to code generation from TypeSpec (Azure JavaScript SDK)


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a Terminology section can be helpful here

Suggested change
> **Terminology used in this guide**
>
> - **Libraries generated from TypeSpec**: Client libraries produced by the **TypeSpec Emitter** (the new generation toolchain).
> Previously referred to as *“modular”/“modularized libraries.”*
> - **Libraries generated with AutoRest**: Client libraries produced by the **AutoRest Code Generator** (previous generation).
> Previously referred to as *“HLC”, "Swagger generator", "OpenAPI Generator"*

This guide helps developers transition their JavaScript/TypeScript applications to use the modularized Azure SDK libraries, also known as Modular SDKs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This guide helps developers transition their JavaScript/TypeScript applications to use the modularized Azure SDK libraries, also known as Modular SDKs.
This guide helps developers transition their JavaScript/TypeScript applications to use the *TypeSpec generated* Azure SDK libraries.


**For new customers of the JavaScript/TypeScript SDK ([azure-sdk-for-js](https://github.com/Azure/azure-sdk-for-js)), please see [quick start guide for modularized libraries](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/modularized-libraries-quickstart.md).**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**For new customers of the JavaScript/TypeScript SDK ([azure-sdk-for-js](https://github.com/Azure/azure-sdk-for-js)), please see [quick start guide for modularized libraries](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/modularized-libraries-quickstart.md).**
**For new customers of the JavaScript/TypeScript SDK ([azure-sdk-for-js](https://github.com/Azure/azure-sdk-for-js)), please see [quick start guide](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/modularized-libraries-quickstart.md).**


## Current status

Several packages released from Modular libraries have already reached General Availability (GA), including `@azure/arm-avs`, `@azure/arm-fabric`, `@azure/arm-oracledatabase`, `@azure/keyvault-admin`. We are actively working on releasing more packages and eventually cover all Azure services. Please find the latest version of those libraries in [npm](https://www.npmjs.com) and give them a try.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Several packages released from Modular libraries have already reached General Availability (GA), including `@azure/arm-avs`, `@azure/arm-fabric`, `@azure/arm-oracledatabase`, `@azure/keyvault-admin`. We are actively working on releasing more packages and eventually cover all Azure services. Please find the latest version of those libraries in [npm](https://www.npmjs.com) and give them a try.
Several packages generated from *TypeSpec* have already reached General Availability (GA), including `@azure/arm-avs`, `@azure/arm-fabric`, `@azure/arm-oracledatabase`, `@azure/keyvault-admin`. We are actively working on releasing more packages and eventually cover all Azure services. Please find the latest version of those libraries in [npm](https://www.npmjs.com) and give them a try.


## Why switching to the modularized libraries?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Why switching to the modularized libraries?
## Library improvements when generating from *TypeSpec*


We recommend reviewing the [complete guide for the modularized libraries](https://devblogs.microsoft.com/azure-sdk/azure-sdk-modularized-libraries-for-javascript/) for full details. Compared to the traditional libraries, Modular SDKs have following key benefits:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We recommend reviewing the [complete guide for the modularized libraries](https://devblogs.microsoft.com/azure-sdk/azure-sdk-modularized-libraries-for-javascript/) for full details. Compared to the traditional libraries, Modular SDKs have following key benefits:
We recommend reviewing the [complete guide](https://devblogs.microsoft.com/azure-sdk/azure-sdk-modularized-libraries-for-javascript/) for full details. Compared to libraries generated with *Autorest*, *TypeSpec code generation* has following key benefits:


1. Subpath exports: Modular SDKs use [subpath exports](https://nodejs.org/api/packages.html#subpath-exports)(available since Node.js version 12.7) to offer layered APIs. In which service client layer from `.` root subpath would provide similar experience to traditional client. And the API layer from `./api` subpath would provide more lightweight client context for shared state across operations.
Copy link
Member

@joheredi joheredi Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Subpath exports: Modular SDKs use [subpath exports](https://nodejs.org/api/packages.html#subpath-exports)(available since Node.js version 12.7) to offer layered APIs. In which service client layer from `.` root subpath would provide similar experience to traditional client. And the API layer from `./api` subpath would provide more lightweight client context for shared state across operations.
1. Subpath exports: Libraries now leverage [subpath exports](https://nodejs.org/api/packages.html#subpath-exports)(introduced in Node.js version 12.7) to provide layered APIs. This means developer can access the familiar `Client` at the root level while also using the `/api` subpath for fine-grained, operation-level imports.

1. Bundle size optimization: Modular SDKs leverage @azure-rest/core-client, which offers improved bundle size efficiency compared to the previous Azure core libraries. This core package provides a general-purpose REST client, while each service-specific package includes its own TypeScript type definitions. These TypeScript types are excluded from the final asset bundle, helping to minimize overall bundle size.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Bundle size optimization: Modular SDKs leverage @azure-rest/core-client, which offers improved bundle size efficiency compared to the previous Azure core libraries. This core package provides a general-purpose REST client, while each service-specific package includes its own TypeScript type definitions. These TypeScript types are excluded from the final asset bundle, helping to minimize overall bundle size.
1. Bundle size optimization: By leveraging the new `/api` subpath export, developers can selectively import only the operations they need. This approach minimizes the overall library footprint in the application bundle, ensuring that only the required pieces are included.

1. Long-running operations: Instead of two methods (beginDoSth and beginDoSthAndWait) in the traditional clients for each long-running operation, which are both redundant and confusing to customers. Modular SDKs offer a single method (doSth) that supports both async and sync usage.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Long-running operations: Instead of two methods (beginDoSth and beginDoSthAndWait) in the traditional clients for each long-running operation, which are both redundant and confusing to customers. Modular SDKs offer a single method (doSth) that supports both async and sync usage.
1. Long-running operations: Based on customer feedback, we simplified the API to make it cleaner and more ergonomic. Previously, clients exposed two methods for each *long-running operation* (`beginDoSth` and `beginDoSthAndWait`), which often felt redundant and confusing. Libraries generated from *TypeSpec* now provide a single method (`doSth`) that supports both async and sync usage, reducing complexity while improving developer experience.



## How to migrate to the modularized libraries?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## How to migrate to the modularized libraries?
## How to migrate to libraries generated from TypeSpec


If you're updating an existing app to use Modular SDKs, focus on these areas:

1. Long-running Operations
1. List Operations
1. Model Property Flattening
Comment on lines +22 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you're updating an existing app to use Modular SDKs, focus on these areas:
1. Long-running Operations
1. List Operations
1. Model Property Flattening
If youre updating an existing application from **libraries generated with AutoRest** to **libraries generated from TypeSpec**, focus on these key areas:
1. **Long-running operations (LROs)** – Updated method signatures and poller behavior
2. **List operations (paging)** – Simplified continuation token handling
3. **Model property flattening****Libraries generated from TypeSpec** no longer support client-side flattening. This decision was based on customer feedback to reduce confusion and maintenance overhead


### Long-running Operations
Copy link
Member

@joheredi joheredi Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Long-running Operations
### Long-running Operations (LROs)


Many operations may take a long time to finish before receiving the desired response named long-running operations. We re-designed LRO in Modular SDKs. The changes mainly are three parts:

- Method signature changes
- LRO poller changes from SimplePollerLike to PollerLike
- Rehydration changes

Comment on lines +30 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Many operations may take a long time to finish before receiving the desired response named long-running operations. We re-designed LRO in Modular SDKs. The changes mainly are three parts:
- Method signature changes
- LRO poller changes from SimplePollerLike to PollerLike
- Rehydration changes
Based on customer feedback, we simplified LROs to make the API **cleaner and more ergonomic**. Three changes matter for migration:
- **Method shape**: two methods → one method
- **Poller type**: `SimplePollerLike``PollerLike` (Promise‑like)
- **Rehydration**: option‑based → helper function

#### Method signature changes

Taking a simple LRO operation as an example with operationId `IntegrationRuntimes_Start`. In traditional client we would have two methods([link](https://github.com/Azure/azure-sdk-for-js/blob/8c1c0027d79354d2b91b318c4ceb52e462f7db92/sdk/datafactory/arm-datafactory/src/operationsInterfaces/integrationRuntimes.ts#L193)).

Comment on lines +36 to +39
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Method signature changes
Taking a simple LRO operation as an example with operationId `IntegrationRuntimes_Start`. In traditional client we would have two methods([link](https://github.com/Azure/azure-sdk-for-js/blob/8c1c0027d79354d2b91b318c4ceb52e462f7db92/sdk/datafactory/arm-datafactory/src/operationsInterfaces/integrationRuntimes.ts#L193)).
#### Method signature changes
Previously (libraries generated with **AutoRest**), each LRO exposed two methods (e.g., `beginStart` and `beginStartAndWait`).
Now (libraries generated from **TypeSpec**), there’s a **single** method that behaves as a poller **and** can be directly awaited.
**AutoRest‑generated (previous)**

```ts
beginStart(
options?: IntegrationRuntimesStartOptionalParams,
): Promise<
SimplePollerLike<
OperationState<IntegrationRuntimesStartResponse>,
IntegrationRuntimesStartResponse
>
>;
beginStartAndWait(
options?: IntegrationRuntimesStartOptionalParams,
): Promise<IntegrationRuntimesStartResponse>;
```
Now we would only have one method in Modular SDK.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Now we would only have one method in Modular SDK.
**TypeSpec‑generated (current)**


```ts
start(options?: IntegrationRuntimesStartOptionalParams): PollerLike<
OperationState<IntegrationRuntimesStartResponse>,
IntegrationRuntimesStartResponse
>;
```
So the before-and-after code would be like below:
| traditional client | Modular |
|----------------------------------------------|--------------------------------------------------------------------------------|
| const result = await beginStartAndWait(); | const result = await start(); // awaiting would get result directly |
| const poller = await beginStart(); | const poller = start(); // directly get the poller |
| | await poller.submitted(); // await the poller submitted if interested |
| const result = await poller.pollUntilDone(); | const result = await poller; // Or const result = await poller.pollUntilDone() |
Comment on lines +61 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
So the before-and-after code would be like below:
| traditional client | Modular |
|----------------------------------------------|--------------------------------------------------------------------------------|
| const result = await beginStartAndWait(); | const result = await start(); // awaiting would get result directly |
| const poller = await beginStart(); | const poller = start(); // directly get the poller |
| | await poller.submitted(); // await the poller submitted if interested |
| const result = await poller.pollUntilDone(); | const result = await poller; // Or const result = await poller.pollUntilDone() |
**Migrate your usage**
```ts
// Before (AutoRest-generated)
const result = await beginStartAndWait();
const poller = await beginStart();
const result2 = await poller.pollUntilDone();
// After (TypeSpec-generated)
const result = await start(); // awaiting returns the final result
const poller = start(); // direct access to the poller
await poller.submitted(); // optional: await initial submission
const result2 = await poller; // or: await poller.pollUntilDone()


#### LRO poller change from SimplePollerLike to PollerLike
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### LRO poller change from SimplePollerLike to PollerLike
#### Poller type: `SimplePollerLike``PollerLike`


In traditional client, the return type of `beginXXX` method is `SimplePollerLike`. Now the return type is changed to `PollerLike` in Modular and this interface is also a PromiseLike. The following table compares `SimplePollerLike` and `PollerLike`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In traditional client, the return type of `beginXXX` method is `SimplePollerLike`. Now the return type is changed to `PollerLike` in Modular and this interface is also a PromiseLike. The following table compares `SimplePollerLike` and `PollerLike`:
TypeSpec‑generated LROs return a `PollerLike`, which is also **Promise‑like**.


| operation | `SimplePollerLike` | `PollerLike` |
| -------------------------------------------------------------------------- | --------------------- | ----------------- |
| return final results | `pollUntilDone()` | `pollUntilDone()` |
| poll | `poll()` | `poll()` |
| access the current state after receiving the response of each poll request | `onProgress()` | `onProgress()` |
| check whether the operation finished | `isDone()` | `isDone` |
| stop polling | `stopPolling()` | N/A |
| check if the polling stopped | `isStopped()` | N/A |
| get the current operation state | `getOperationState()` | `operationState` |
| access the final result | `getResult()` | `result` |
| serialize the poller state | `toString()` | `serialize()` |
| wait the poller submitted successfully | N/A | `submitted()` |

Please note the operation `getOperationState(): TState` is changed to attribute `operationState: TState | undefined`, so the value could be `undefined` if the poller is not initialized yet.
Comment on lines +73 to +86
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| operation | `SimplePollerLike` | `PollerLike` |
| -------------------------------------------------------------------------- | --------------------- | ----------------- |
| return final results | `pollUntilDone()` | `pollUntilDone()` |
| poll | `poll()` | `poll()` |
| access the current state after receiving the response of each poll request | `onProgress()` | `onProgress()` |
| check whether the operation finished | `isDone()` | `isDone` |
| stop polling | `stopPolling()` | N/A |
| check if the polling stopped | `isStopped()` | N/A |
| get the current operation state | `getOperationState()` | `operationState` |
| access the final result | `getResult()` | `result` |
| serialize the poller state | `toString()` | `serialize()` |
| wait the poller submitted successfully | N/A | `submitted()` |
Please note the operation `getOperationState(): TState` is changed to attribute `operationState: TState | undefined`, so the value could be `undefined` if the poller is not initialized yet.
| Capability | AutoRest (`SimplePollerLike`) | TypeSpec (`PollerLike`) |
|---------------------------------------------|-------------------------------|-------------------------|
| Return final results | `pollUntilDone()` | `pollUntilDone()` |
| Poll | `poll()` | `poll()` |
| Observe progress | `onProgress()` | `onProgress()` |
| Check completion | `getOperationState().isCompleted`/`isDone()` | `isDone` |
| Stop / check stopped | `stopPolling()` / `isStopped()` | N/A |
| Read current state | `getOperationState()` | `operationState` |
| Access final result | `getResult()` | `result` |
| Serialize poller state | `toString()` | `serialize()` |
| Await initial submission | N/A | `submitted()` |
> **Note:** `getOperationState(): TState` becomes the property `operationState?: TState`. Guard for `undefined` before access:


```ts
const status = poller.getOperationState().status;
```

now

```ts
const status = poller?.operationState?.status;
```
Comment on lines +88 to +96
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
```ts
const status = poller.getOperationState().status;
```
now
```ts
const status = poller?.operationState?.status;
```
```ts
// Before
const status = poller.getOperationState().status;
// Now
const status = poller?.operationState?.status;


If you want to serialize a poller, use the `serialize` instead.

```ts
const serializeState = poller.toString();
```

now

```ts
const serializeState = await poller.serialize();
```
Comment on lines +98 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
If you want to serialize a poller, use the `serialize` instead.
```ts
const serializeState = poller.toString();
```
now
```ts
const serializeState = await poller.serialize();
```
**Serialization change**
```ts
// Before
const serialized = poller.toString();
// Now
const serialized = await poller.serialize();

#### Rehydration change
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Rehydration change
#### Rehydration (restoring a poller)


We also change the way to restore an existing LRO. The main change is we deliver the restore functionality as a helper function not binding with methods.

In traditional client we build an option `resumeFrom`.

```ts
export interface IntegrationRuntimesStartOptionalParams
extends coreClient.OperationOptions {
/** A serialized poller which can be used to resume an existing paused Long-Running-Operation. */
resumeFrom?: string;
}
```
Now we build a client-level helper for this.
```ts
export function restorePoller<TResponse extends PathUncheckedResponse, TResult>(
client: DataFactoryManagementClient,
serializedState: string,
sourceOperation: (
...args: any[]
) => PollerLike<OperationState<TResult>, TResult>,
options?: RestorePollerOptions<TResult>,
): PollerLike<OperationState<TResult>, TResult>
```

The before-and-after code would be like:

```ts
// traditional client
const result = await client.beginStartAndWait({resumeFrom: serializedState});

// Modular
const result = await restorePoller(client, serializedState, client.start);
```
If you are interested in more details in core-lro and here is the [migration guide](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-lro/docs/MIGRATION.md).
Comment on lines +111 to +143
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
We also change the way to restore an existing LRO. The main change is we deliver the restore functionality as a helper function not binding with methods.
In traditional client we build an option `resumeFrom`.
```ts
export interface IntegrationRuntimesStartOptionalParams
extends coreClient.OperationOptions {
/** A serialized poller which can be used to resume an existing paused Long-Running-Operation. */
resumeFrom?: string;
}
```
Now we build a client-level helper for this.
```ts
export function restorePoller<TResponse extends PathUncheckedResponse, TResult>(
client: DataFactoryManagementClient,
serializedState: string,
sourceOperation: (
...args: any[]
) => PollerLike<OperationState<TResult>, TResult>,
options?: RestorePollerOptions<TResult>,
): PollerLike<OperationState<TResult>, TResult>
```
The before-and-after code would be like:
```ts
// traditional client
const result = await client.beginStartAndWait({resumeFrom: serializedState});
// Modular
const result = await restorePoller(client, serializedState, client.start);
```
If you are interested in more details in core-lro and here is the [migration guide](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-lro/docs/MIGRATION.md).
Rehydration moved from an operation option (`resumeFrom`) to a **client‑level helper**.
**Before → After**
```ts
// Before (AutoRest-generated)
const result = await client.beginStartAndWait({ resumeFrom: serializedState });
// After (TypeSpec-generated)
const result = await restorePoller(client, serializedState, client.start);

For more detail, see the core‑lro migration guide:
https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-lro/docs/MIGRATION.md


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For more detail, see the core‑lro migration guide:
https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-lro/docs/MIGRATION.md
---
### Quick migration checklist
- Replace `beginXxxAndWait()``await xxx()`.
- Replace `await beginXxx()``const poller = xxx()`.
- Replace `poller.toString()``await poller.serialize()`.
- Replace `poller.getOperationState()``poller.operationState` (guard for `undefined`).
- If you previously used `resumeFrom`, switch to `restorePoller(client, serialized, client.xxx)`.
- If you depended on `stopPolling()`/`isStopped()`, revisit your control flow (these are not exposed on `PollerLike`).
---

### List Operations
In Modular we adjusted paging interfaces a little for better experience and mainly are two parts:
- Remove un-supported maxpagesize in PageSetting
- Use `continuationToken` to replace the helper `getContinuationToken`
Comment on lines +145 to +148
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### List Operations
In Modular we adjusted paging interfaces a little for better experience and mainly are two parts:
- Remove un-supported maxpagesize in PageSetting
- Use `continuationToken` to replace the helper `getContinuationToken`
### List operations (paging)
Paging has been simplified in libraries generated from TypeSpec. Two main changes:
- **Removed unsupported `maxpagesize`**
- **Replaced `getContinuationToken` helper with direct `continuationToken` property**


#### Remove un-supported maxpagesize in PageSetting
The `maxpagesize` is not supported in traditional client so in Modular we remove this setting within PageSettings. These changes are supposed to have no impact for customers.

#### Remove the helper `getContinuationToken`
In traditional client we build an util function to help customers to get the continuation token([here](https://github.com/Azure/azure-sdk-for-js/blob/735677407c4fbbceea95200f6d6de00e29804740/sdk/datadog/arm-datadog/src/pagingHelper.ts#L22-L29)).

So we could reference the token by code.

```ts
const firstPage = await iter.byPage().next();
const continuationToken = getContinuationToken(firstPage);
```

Now we directly deliver the `continuationToken` with byPage return.

```ts
export type ContinuablePage<TElement, TPage = TElement[]> = TPage & {
/**
* The token that keeps track of where to continue the iterator
*/
continuationToken?: string;
};
```
So we could reference the token like below:
```ts
const firstPage = await iter.byPage().next();
const continuationToken = firstPage.value.continuationToken;
```
Comment on lines +150 to +177
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#### Remove un-supported maxpagesize in PageSetting
The `maxpagesize` is not supported in traditional client so in Modular we remove this setting within PageSettings. These changes are supposed to have no impact for customers.
#### Remove the helper `getContinuationToken`
In traditional client we build an util function to help customers to get the continuation token([here](https://github.com/Azure/azure-sdk-for-js/blob/735677407c4fbbceea95200f6d6de00e29804740/sdk/datadog/arm-datadog/src/pagingHelper.ts#L22-L29)).
So we could reference the token by code.
```ts
const firstPage = await iter.byPage().next();
const continuationToken = getContinuationToken(firstPage);
```
Now we directly deliver the `continuationToken` with byPage return.
```ts
export type ContinuablePage<TElement, TPage = TElement[]> = TPage & {
/**
* The token that keeps track of where to continue the iterator
*/
continuationToken?: string;
};
```
So we could reference the token like below:
```ts
const firstPage = await iter.byPage().next();
const continuationToken = firstPage.value.continuationToken;
```
#### `maxpagesize` removed
The `maxpagesize` setting was never supported in AutoRest-generated clients, so it has been removed from `PageSettings`. No behavioral impact is expected.
#### Continuation token access simplified
Previously, you needed a helper function to extract the continuation token:
**AutoRest-generated (previous)**
```ts
const firstPage = await iter.byPage().next();
const continuationToken = getContinuationToken(firstPage);

Now, the token is exposed directly on the page object:

TypeSpec-generated (current)

export type ContinuablePage<TElement, TPage = TElement[]> = TPage & {
  /** Token to continue iteration */
  continuationToken?: string;
};

const firstPage = await iter.byPage().next();
const continuationToken = firstPage.value.continuationToken;


## Model Property Flattening

Client libraries represent entities transferred to and from Azure services as model types. For the model types, in the traditional client we have supported the autorest extension [x-ms-client-flatten](https://azure.github.io/autorest/extensions/#x-ms-client-flatten). This extension allows to flatten deeply nested payloads into a top-level object structure. For example a payload that looks like this on the wire:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Client libraries represent entities transferred to and from Azure services as model types. For the model types, in the traditional client we have supported the autorest extension [x-ms-client-flatten](https://azure.github.io/autorest/extensions/#x-ms-client-flatten). This extension allows to flatten deeply nested payloads into a top-level object structure. For example a payload that looks like this on the wire:
Previously, **libraries generated with AutoRest** supported the `x-ms-client-flatten` extension, which allowed deeply nested payloads to be flattened into a top-level object structure. For example, a payload like this:


```json
{
"hcxEnterpriseSite": {
"name": "hcxEnterpriseSiteName",
"properties": {
"provisioningState": "succeed",
"activationKey": "value2",
"status": "ok"
},
},
}
```
Can be transformed into the following client model and see [generated code](https://github.com/Azure/azure-sdk-for-js/blob/835b3dca8d8c635c1471a8264b025409a75298fc/sdk/avs/arm-avs/src/models/index.ts#L1196C1-L1213C2):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Can be transformed into the following client model and see [generated code](https://github.com/Azure/azure-sdk-for-js/blob/835b3dca8d8c635c1471a8264b025409a75298fc/sdk/avs/arm-avs/src/models/index.ts#L1196C1-L1213C2):
would generate a model where `activationKey` and other properties were surfaced at the top level:

```ts
/** An HCX Enterprise Site resource */
export interface HcxEnterpriseSite extends ProxyResource {
/**
* The provisioning state of the resource.
* NOTE: This property will not be serialized. It can only be populated by the server.
*/
readonly provisioningState?: HcxEnterpriseSiteProvisioningState;
/**
* The activation key
* NOTE: This property will not be serialized. It can only be populated by the server.
*/
readonly activationKey?: string;
/**
* The status of the HCX Enterprise Site
* NOTE: This property will not be serialized. It can only be populated by the server.
*/
readonly status?: HcxEnterpriseSiteStatus;
}
```

Modular SDKs no longer support flattening to reduce confusion and maintenance overhead. So now [the model](https://github.com/azure/azure-sdk-for-js/blob/181311fe630b5609e78d55306ad2242bb881dacf/sdk/avs/arm-avs/src/models/models.ts#L3171-L3174) would be generated like below:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Modular SDKs no longer support flattening to reduce confusion and maintenance overhead. So now [the model](https://github.com/azure/azure-sdk-for-js/blob/181311fe630b5609e78d55306ad2242bb881dacf/sdk/avs/arm-avs/src/models/models.ts#L3171-L3174) would be generated like below:
### What changed?
**Libraries generated from TypeSpec** no longer support client-side flattening. This decision was based on customer feedback to reduce confusion and maintenance overhead. Models now preserve the original structure, so properties are grouped under a `properties` object (as defined in TypeSpec):

```ts
/** An HCX Enterprise Site resource */
export interface HcxEnterpriseSite extends ProxyResource {
/** The resource-specific properties for this resource. */
properties?: HcxEnterpriseSiteProperties;
}

/** The properties of an HCX Enterprise Site */
export interface HcxEnterpriseSiteProperties {
/** The provisioning state of the resource. */
readonly provisioningState?: HcxEnterpriseSiteProvisioningState;
/** The activation key */
readonly activationKey?: string;
/** The status of the HCX Enterprise Site */
readonly status?: HcxEnterpriseSiteStatus;
}
```

Which means for these changes, we need to update our code from `result.activationKey` to `result.properties?.activationKey`. So the before-and-after code would be like:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Which means for these changes, we need to update our code from `result.activationKey` to `result.properties?.activationKey`. So the before-and-after code would be like:
### What does this mean for you?
Update your code to access nested properties through `properties`. For example:


```ts
// traditional client
const result = await client.hcxEnterpriseSites.get("resourceGroupName", "privateCloudName", "hcxEnterpriseSiteName");
console.log(result.activationKey);

// Modular client
const result = await client.hcxEnterpriseSites.get("resourceGroupName", "privateCloudName", "hcxEnterpriseSiteName");
console.log(result.properties?.activationKey);
```

Please note for Azure models, majority of property flatten happened in `properties` property.
Copy link
Member

@joheredi joheredi Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Please note for Azure models, majority of property flatten happened in `properties` property.
> **Tip:** In most Azure resource models, flattening occurred under the `properties` bag, so expect to adjust references accordingly.



## Need help

If you have encountered an issue during migration, please file an issue via [Github Issues](https://github.com/Azure/azure-sdk-for-js/issues) and make sure you add the 'Preview' label to the issue.
Loading
Loading