|
| 1 | +--- |
| 2 | +title: Large payload support with Durable Task Scheduler (Preview) |
| 3 | +description: Learn how to use preview large payload support in Durable Functions and the Durable Task SDKs with Durable Task Scheduler and Azure Blob Storage. |
| 4 | +ms.topic: conceptual |
| 5 | +ms.date: 03/14/2026 |
| 6 | +ms.author: torosent |
| 7 | +ms.service: azure-functions |
| 8 | +ms.subservice: durable-task-scheduler |
| 9 | +ms.devlang: csharp |
| 10 | +zone_pivot_groups: azure-durable-approach |
| 11 | +--- |
| 12 | + |
| 13 | +# Large payload support with Durable Task Scheduler (Preview) |
| 14 | + |
| 15 | +Large payload support lets your app pass orchestration inputs and activity outputs that exceed the [Durable Task Scheduler](durable-task-scheduler.md) message size limit. When a payload goes over the configured threshold, the framework stores the serialized payload in Azure Blob Storage and sends a small reference through Durable Task Scheduler. |
| 16 | + |
| 17 | +This feature is available only for C# apps: |
| 18 | + |
| 19 | +- [Durable Functions](../durable-functions-overview.md) with the .NET isolated worker |
| 20 | +- [.NET Durable Task SDK](durable-task-overview.md) |
| 21 | + |
| 22 | +If your workflow stores data in Blob Storage and passes only a URI or identifier, keep using that pattern. Use large payload support when your orchestration logic must pass the payload between durable operations. For general guidance, see [Data persistence and serialization in Durable Functions](../durable-functions-serialization-and-persistence.md#keep-inputs-and-outputs-small). |
| 23 | + |
| 24 | +## Supported frameworks |
| 25 | + |
| 26 | +This table shows large payload support by framework. |
| 27 | + |
| 28 | +| Framework | Support status | What you need | |
| 29 | +| --- | --- | --- | |
| 30 | +| Durable Functions | Supported in .NET isolated C# | Use Durable Task Scheduler as the storage provider and use `AzureWebJobsStorage` for payload blobs | |
| 31 | +| Durable Task SDKs | Supported in .NET | Use `Microsoft.DurableTask.Extensions.AzureBlobPayloads` with Azure Blob Storage | |
| 32 | +| JavaScript, Python, PowerShell, and Java | Not available | Use external storage and pass references between durable operations | |
| 33 | + |
| 34 | +## How it works |
| 35 | + |
| 36 | +When you enable large payload support, the runtime follows the same high level flow in both hosting models: |
| 37 | + |
| 38 | +1. It serializes the orchestration input or activity output. |
| 39 | +1. If the payload size exceeds your configured threshold, the runtime compresses the payload with gzip. |
| 40 | +1. It writes the compressed payload to Azure Blob Storage. |
| 41 | +1. It sends a blob reference through Durable Task Scheduler instead of the full payload. |
| 42 | +1. The runtime automatically resolves the reference before your orchestrator or activity code reads the value. |
| 43 | + |
| 44 | +The current .NET samples use deterministic, low-compressibility 1.5 MiB payloads. That keeps the stored blob size representative, even though the runtime writes blobs with gzip content encoding. |
| 45 | + |
| 46 | +Large payload support changes how payloads move through the runtime. It doesn't change the recommendation to keep durable state as small as practical. |
| 47 | + |
| 48 | +## Choose the right pattern |
| 49 | + |
| 50 | +Use the simplest pattern for your scenario. |
| 51 | + |
| 52 | +| Use this pattern | When to use it | |
| 53 | +| --- | --- | |
| 54 | +| Large payload support | Your orchestration passes the payload between durable operations, and the payload exceeds the scheduler message limit | |
| 55 | +| External storage plus references | Your activities load data directly from storage, and you want the smallest possible orchestration state | |
| 56 | + |
| 57 | +## Enable large payload support |
| 58 | + |
| 59 | +::: zone pivot="durable-functions" |
| 60 | + |
| 61 | +Large payload support in Durable Functions is available only for .NET isolated C# apps that use Durable Task Scheduler as the storage provider. |
| 62 | + |
| 63 | +# [C#](#tab/csharp) |
| 64 | + |
| 65 | +Before you enable the feature, make sure your app: |
| 66 | + |
| 67 | +- Uses the .NET isolated worker. |
| 68 | +- References `Microsoft.Azure.Functions.Worker.Extensions.DurableTask` and `Microsoft.Azure.Functions.Worker.Extensions.DurableTask.AzureManaged`. |
| 69 | +- Sets `AzureWebJobsStorage` to the storage account that holds externalized payloads. |
| 70 | +- Sets `DTS_CONNECTION_STRING` and `TASKHUB_NAME` for the target scheduler and task hub. |
| 71 | + |
| 72 | +Then enable large payload storage in [host.json](../durable-functions-bindings.md#host-json): |
| 73 | + |
| 74 | +```json |
| 75 | +{ |
| 76 | + "version": "2.0", |
| 77 | + "extensions": { |
| 78 | + "durableTask": { |
| 79 | + "storageProvider": { |
| 80 | + "type": "azureManaged", |
| 81 | + "connectionStringName": "DTS_CONNECTION_STRING", |
| 82 | + "largePayloadStorageEnabled": true, |
| 83 | + "largePayloadStorageThresholdBytes": 900000 |
| 84 | + }, |
| 85 | + "hubName": "%TASKHUB_NAME%" |
| 86 | + } |
| 87 | + } |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +Set `largePayloadStorageThresholdBytes` below the Durable Task Scheduler message size boundary so the runtime externalizes payloads before they approach the limit. |
| 92 | + |
| 93 | +Use the standard Durable Functions APIs in your orchestrator and activity code. The runtime automatically resolves blob references before `context.GetInput<T>()` and `context.CallActivityAsync<T>()` return data. |
| 94 | + |
| 95 | +By default, the extension writes externalized payloads to the `durabletask-payloads` container in the storage account configured by `AzureWebJobsStorage`. |
| 96 | + |
| 97 | +For end-to-end examples, see these samples: |
| 98 | + |
| 99 | +- [Durable Functions large payload sample](https://github.com/Azure-Samples/Durable-Task-Scheduler/tree/main/samples/durable-functions/dotnet/LargePayload) |
| 100 | +- [Durable Functions large payload fan-out/fan-in sample](https://github.com/Azure-Samples/Durable-Task-Scheduler/tree/main/samples/durable-functions/dotnet/LargePayloadFanOutFanIn) |
| 101 | + |
| 102 | +# [JavaScript](#tab/javascript) |
| 103 | + |
| 104 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 105 | + |
| 106 | +# [Python](#tab/python) |
| 107 | + |
| 108 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 109 | + |
| 110 | +# [PowerShell](#tab/powershell) |
| 111 | + |
| 112 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 113 | + |
| 114 | +# [Java](#tab/java) |
| 115 | + |
| 116 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 117 | + |
| 118 | +--- |
| 119 | + |
| 120 | +::: zone-end |
| 121 | + |
| 122 | +::: zone pivot="durable-task-sdks" |
| 123 | + |
| 124 | +Large payload support in the Durable Task SDKs is available only for .NET apps. |
| 125 | + |
| 126 | +# [C#](#tab/csharp) |
| 127 | + |
| 128 | +Install the Azure Blob payload extension package: |
| 129 | + |
| 130 | +```bash |
| 131 | +dotnet add package Microsoft.DurableTask.Extensions.AzureBlobPayloads |
| 132 | +``` |
| 133 | + |
| 134 | +Install the Azure Managed client and worker packages for Durable Task Scheduler: |
| 135 | + |
| 136 | +```bash |
| 137 | +dotnet add package Microsoft.DurableTask.Client.AzureManaged |
| 138 | +dotnet add package Microsoft.DurableTask.Worker.AzureManaged |
| 139 | +``` |
| 140 | + |
| 141 | +Register an externalized payload store, choose a threshold, and enable payload resolution on both the client and the worker: |
| 142 | + |
| 143 | +```csharp |
| 144 | +builder.Services.AddExternalizedPayloadStore(options => |
| 145 | +{ |
| 146 | + options.ExternalizeThresholdBytes = 900_000; |
| 147 | + options.ConnectionString = builder.Configuration["PAYLOAD_STORAGE_CONNECTION_STRING"] |
| 148 | + ?? "UseDevelopmentStorage=true"; |
| 149 | + options.ContainerName = "durabletask-payloads"; |
| 150 | +}); |
| 151 | + |
| 152 | +builder.Services.AddDurableTaskClient(client => |
| 153 | +{ |
| 154 | + client.UseDurableTaskScheduler(schedulerConnectionString); |
| 155 | + client.UseExternalizedPayloads(); |
| 156 | +}); |
| 157 | + |
| 158 | +builder.Services.AddDurableTaskWorker(worker => |
| 159 | +{ |
| 160 | + worker.UseDurableTaskScheduler(schedulerConnectionString); |
| 161 | + worker.UseExternalizedPayloads(); |
| 162 | +}); |
| 163 | +``` |
| 164 | + |
| 165 | +If you use Microsoft Entra ID instead of a storage connection string, set `options.AccountUri` and `options.Credential`. The sample uses `DefaultAzureCredential` and can optionally target a user-assigned managed identity. |
| 166 | + |
| 167 | +Keep `ExternalizeThresholdBytes` at or below `1,048,576` bytes. The sample uses `900,000` bytes so payloads are offloaded before they approach the 1 MiB scheduler message boundary. |
| 168 | + |
| 169 | +For an end-to-end .NET example, see the [Durable Task SDK large payload sample](https://github.com/Azure-Samples/Durable-Task-Scheduler/tree/main/samples/durable-task-sdks/dotnet/LargePayload). |
| 170 | + |
| 171 | +# [JavaScript](#tab/javascript) |
| 172 | + |
| 173 | +Large payload support with Durable Task Scheduler is available only for the .NET Durable Task SDK. |
| 174 | + |
| 175 | +# [PowerShell](#tab/powershell) |
| 176 | + |
| 177 | +Large payload support with Durable Task Scheduler is available only for the .NET Durable Task SDK. |
| 178 | + |
| 179 | +# [Python](#tab/python) |
| 180 | + |
| 181 | +Large payload support with Durable Task Scheduler is available only for the .NET Durable Task SDK. |
| 182 | + |
| 183 | +# [Java](#tab/java) |
| 184 | + |
| 185 | +Large payload support with Durable Task Scheduler is available only for the .NET Durable Task SDK. |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +::: zone-end |
| 190 | + |
| 191 | +## Environment variable configuration |
| 192 | + |
| 193 | +::: zone pivot="durable-functions" |
| 194 | + |
| 195 | +Use these local settings or app settings with the current Durable Functions samples. |
| 196 | + |
| 197 | +# [C#](#tab/csharp) |
| 198 | + |
| 199 | +| Setting | Description | Sample default | |
| 200 | +| --- | --- | --- | |
| 201 | +| `FUNCTIONS_WORKER_RUNTIME` | Azure Functions isolated worker runtime | `dotnet-isolated` | |
| 202 | +| `AzureWebJobsStorage` | Storage for Functions host state and payload blobs | `UseDevelopmentStorage=true` locally | |
| 203 | +| `DTS_CONNECTION_STRING` | Durable Task Scheduler connection string | `Endpoint=http://localhost:8080;Authentication=None` | |
| 204 | +| `TASKHUB_NAME` | Target task hub | `default` | |
| 205 | +| `PAYLOAD_SIZE_BYTES` | Payload size used by the starter or generated by each activity | `1572864` | |
| 206 | +| `ACTIVITY_COUNT` | Number of parallel activities in the fan-out/fan-in sample only | `3` | |
| 207 | + |
| 208 | +The `ACTIVITY_COUNT` setting is used only by the `LargePayloadFanOutFanIn` sample. The `LargePayload` round-trip sample doesn't read it. |
| 209 | + |
| 210 | +# [JavaScript](#tab/javascript) |
| 211 | + |
| 212 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 213 | + |
| 214 | +# [Python](#tab/python) |
| 215 | + |
| 216 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 217 | + |
| 218 | +# [PowerShell](#tab/powershell) |
| 219 | + |
| 220 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 221 | + |
| 222 | +# [Java](#tab/java) |
| 223 | + |
| 224 | +Large payload support with Durable Task Scheduler is available only for .NET isolated C# Durable Functions apps. |
| 225 | + |
| 226 | +--- |
| 227 | + |
| 228 | +::: zone-end |
| 229 | + |
| 230 | +::: zone pivot="durable-task-sdks" |
| 231 | + |
| 232 | +Use these environment variables with the current .NET Durable Task SDK sample. |
| 233 | + |
| 234 | +# [C#](#tab/csharp) |
| 235 | + |
| 236 | +| Variable | Description | Sample default | |
| 237 | +| --- | --- | --- | |
| 238 | +| `DURABLE_TASK_SCHEDULER_CONNECTION_STRING` | Durable Task Scheduler connection string | `Endpoint=http://localhost:8080;TaskHub=default;Authentication=None` | |
| 239 | +| `PAYLOAD_STORAGE_CONNECTION_STRING` | Blob storage connection string for externalized payloads | `UseDevelopmentStorage=true` | |
| 240 | +| `PAYLOAD_STORAGE_ACCOUNT_URI` | Blob account URI for identity-based payload storage access | unset | |
| 241 | +| `PAYLOAD_CONTAINER_NAME` | Blob container for externalized payloads | `durabletask-payloads` | |
| 242 | +| `PAYLOAD_SIZE_BYTES` | Default payload size used by the run endpoint | `1572864` | |
| 243 | +| `EXTERNALIZE_THRESHOLD_BYTES` | Blob offload threshold | `900000` | |
| 244 | +| `PAYLOAD_STORAGE_MANAGED_IDENTITY_CLIENT_ID` | Optional user-assigned managed identity client ID for storage access | unset | |
| 245 | +| `AZURE_CLIENT_ID` | Alternate way to select a user-assigned managed identity | unset | |
| 246 | +| `ASPNETCORE_URLS` | Listen URLs for the sample's HTTP host | framework default | |
| 247 | + |
| 248 | +If `PAYLOAD_STORAGE_CONNECTION_STRING` isn't set and `PAYLOAD_STORAGE_ACCOUNT_URI` is provided, the sample uses `DefaultAzureCredential`. If you need a specific user-assigned identity, set `PAYLOAD_STORAGE_MANAGED_IDENTITY_CLIENT_ID` or `AZURE_CLIENT_ID`. |
| 249 | + |
| 250 | +# [JavaScript](#tab/javascript) |
| 251 | + |
| 252 | +This sample is shown for .NET, Java, and Python. |
| 253 | + |
| 254 | +# [PowerShell](#tab/powershell) |
| 255 | + |
| 256 | +This sample is shown for .NET, Java, and Python. |
| 257 | + |
| 258 | +# [Python](#tab/python) |
| 259 | + |
| 260 | +This sample is shown for .NET, Java, and Python. |
| 261 | + |
| 262 | +# [Java](#tab/java) |
| 263 | + |
| 264 | +This sample is shown for .NET, Java, and Python. |
| 265 | + |
| 266 | +--- |
| 267 | + |
| 268 | +::: zone-end |
| 269 | + |
| 270 | +## Azure permissions |
| 271 | + |
| 272 | +When you use Azure resources instead of local emulators, the app identity needs access to Durable Task Scheduler and Blob Storage: |
| 273 | + |
| 274 | +- Grant `Durable Task Data Contributor` on the app's task hub. |
| 275 | +- Grant `Storage Blob Data Contributor` on the storage account that stores payload blobs. |
| 276 | + |
| 277 | +These permissions apply to Durable Functions apps and Durable Task SDK apps that use a managed identity. |
| 278 | + |
| 279 | +## Check that payload offload works |
| 280 | + |
| 281 | +After you enable payload offload, run an orchestration with an input or output larger than your configured threshold. Then check for both signals: |
| 282 | + |
| 283 | +- The orchestration completes successfully even though the payload exceeds 1 MiB. |
| 284 | +- Blob entries appear in the `durabletask-payloads` container. |
| 285 | + |
| 286 | +For local development, run this Azure CLI command to inspect the container: |
| 287 | + |
| 288 | +```azurecli |
| 289 | +az storage blob list \ |
| 290 | + --connection-string "UseDevelopmentStorage=true" \ |
| 291 | + --container-name durabletask-payloads \ |
| 292 | + --output table |
| 293 | +``` |
| 294 | + |
| 295 | +The sample apps also validate the round trip: |
| 296 | + |
| 297 | +- The Durable Functions samples return a small summary object that confirms the input and output sizes. |
| 298 | +- The .NET Durable Task SDK sample prints whether the run creates new payload blobs. |
| 299 | + |
| 300 | +Because the runtime stores externalized payloads with gzip content encoding, Azure reports the compressed on-disk blob size. With the current low-compressibility sample payloads, those blob sizes should stay reasonably close to the logical payload size. |
| 301 | + |
| 302 | +> [!NOTE] |
| 303 | +> Purging orchestration instances doesn't currently delete the corresponding externalized payload blobs from Azure Blob Storage. If you need to remove those payloads, delete the blobs from the storage account separately. |
| 304 | +
|
| 305 | +## Next steps |
| 306 | + |
| 307 | +> [!div class="nextstepaction"] |
| 308 | +> [Configure Durable Functions with Durable Task Scheduler](quickstart-durable-task-scheduler.md) |
| 309 | +
|
| 310 | +> [!div class="nextstepaction"] |
| 311 | +> [Create an app with the Durable Task SDKs](quickstart-portable-durable-task-sdks.md) |
0 commit comments