When AWS announced Lambda durable functions in December 2025, I had the reaction a lot of .NET developers probably had: excitement, followed immediately by disappointment. Python and Node.js only. No .NET support, and no indication it was coming.
The feature is exactly what I'd wanted for years. Write Step Functions workflows in your native language. Keep them inside a Lambda handler. Get automatic checkpointing and the ability to pause execution for up to a year without paying for idle compute. And for half a year, C# developers just had to watch from the sidelines.
As of July 2026, that's done. The AWS Durable Execution SDK for .NET is now released.
What Durable Functions Actually Are
Lambda durable functions use a checkpoint-and-replay model. Your handler runs top-to-bottom like normal code, but SDK primitives like Step and Wait mark points where progress is saved. If the function is interrupted (timeout, failure, or a deliberate pause), Lambda saves a checkpoint log. On the next invocation, the SDK replays previously completed steps by returning their stored results without re-executing the code, then resumes from where it left off.
The core components:
- Steps — execute a block of code and checkpoint the result. On replay, return the stored value.
- Waits — pause execution until an external signal arrives or a timer expires. No compute charges during the wait.
- Invoke — call another Lambda function and checkpoint the result. The calling function doesn't consume compute while waiting.
- Parallel / Map — fan out work and checkpoint all results.
This lets you express workflows like "validate an order, charge the payment, wait for human approval (up to 72 hours), then ship" as a single function with sequential logic. Each step is durable. A failure at step 3 doesn't re-run steps 1 and 2.
Why This Matters More for .NET Than You'd Think
.NET teams on AWS tend to build the kinds of systems that need multi-step orchestration: order pipelines, approval workflows, saga patterns across microservices. That work landed on Step Functions because it was the only durable orchestration option in the serverless space. The fit was always awkward: your application logic is in C# with full type safety and test coverage, but the orchestration layer is Amazon State Language JSON in a separate service. Separate IAM roles, separate deployment, no access to your type system.
Durable functions bring that orchestration back into the application layer. The workflow is C# code, tested with your test framework, deployed with your deployment tooling, and composed with your existing services through normal method calls. For teams that tolerated Step Functions because nothing better existed, this is the better thing.
What the SDK Looks Like
The .NET durable execution SDK ships as a NuGet package that you include in your deployment. Unlike the Node.js and Python runtimes, .NET runtimes don't bundle the SDK. You reference it explicitly, which also means you control the version.
A durable function handler looks roughly like this:
public async Task<OrderResult> HandleAsync(OrderRequest request, IDurableExecution durable)
{
var validation = await durable.Step("validate", async () =>
{
return await _validator.ValidateOrder(request);
});
if (!validation.IsValid)
return OrderResult.Failed(validation.Errors);
var payment = await durable.Step("charge", async () =>
{
return await _payments.Charge(request.PaymentMethod, request.Total);
});
await durable.Wait("approval", new WaitConfig
{
Timeout = TimeSpan.FromHours(72)
});
var shipment = await durable.Step("ship", async () =>
{
return await _shipping.CreateShipment(request.Items, request.Address);
});
return OrderResult.Success(shipment.TrackingId);
}
Each step's result is checkpointed. If the function resumes after the payment step, it won't re-charge the customer. It replays the stored result and moves on.
The Wait Was Worth It
I'll be honest: when durable functions launched without .NET, I wasn't optimistic. Seven months isn't bad on paper, but .NET on AWS has a history of feature gaps that stretch into years. The runtime itself is one of the best-performing options on Lambda — fast cold starts with AoT, low memory footprint, strong tooling. But new Lambda capabilities often ship for Python and Node.js first, with .NET support arriving late or never. That track record made the silence at launch feel permanent.
Seven months later, here we are. A standalone NuGet package, dedicated documentation, and a proper SDK reference. That's faster parity than I expected, and it suggests the durable functions team considered .NET a priority rather than an afterthought.
For teams running .NET on Lambda today, this opens up patterns that previously required either Step Functions or custom state management with DynamoDB and SQS. Multi-step order processing, saga patterns with compensation, human-in-the-loop approvals, long-running batch coordination. All expressible as sequential C# code with automatic durability.
I'm planning to integrate this into one of our existing workflows at Oproto that currently uses Step Functions for what is fundamentally application-level orchestration.
What I Want to Build on Top of This
The SDK works. But the developer experience leaves room to grow. Every step requires a string name, a lambda wrapper, and manual serialization awareness. That's fine for a three-step workflow. For a twenty-step saga with compensation logic, it's a lot of ceremony around what should just be methods.
I keep looking at it and seeing a source generator. Decorate a method with [Step], let the generator emit the checkpoint name (derived from the method name, refactor-safe), the replay logic, and the serialization context. You write plain async methods. The generator writes the durable plumbing. AoT-safe by construction because the generator controls everything at compile time.
Same philosophy as FluentDynamoDB: source generators turning declarative C# into runtime-free infrastructure code. I'll have more to share once I've validated the SDK's extension points.
Resources