LLMs  

Benchmarking .NET Lambda Cold Starts with Durable Workflows

AWS Lambda is attractive for .NET applications because it removes the need to manage servers while automatically scaling execution environments.

For ordinary Lambda functions, cold starts are already an important performance consideration. For durable workflows, the problem becomes more interesting because a workflow can execute multiple steps, pause, resume, retry failed operations, and potentially run for a long period.

AWS announced general availability of the AWS Lambda Durable Execution SDK for .NET in July 2026. The SDK provides C# developers with durable steps, waits, callbacks, durable Lambda invocation, and local testing capabilities.

That creates an important performance question for .NET teams:

How much startup overhead does a durable workflow introduce, and how does that overhead compare with the actual work performed by the workflow?

This article presents a practical benchmarking methodology rather than claiming a universal cold-start number. Actual latency depends on runtime version, memory configuration, deployment package, initialization code, workload, concurrency, and AWS environment.

What Is a Lambda Cold Start?

A cold start occurs when Lambda needs to create a new execution environment before running the function.

A simplified lifecycle is:

Incoming Request
       |
       v
Create Execution Environment
       |
       v
Initialize Runtime
       |
       v
Initialize Application
       |
       v
Run Handler

Lambda describes the initialization phase as including environment setup, runtime startup, code loading, and initialization code outside the handler. A reused environment can avoid this initialization work and is commonly referred to as a warm invocation.

For a latency-sensitive API, this distinction matters:

Cold invocation
----------------
Request
  |
  +--> Initialization
  |
  +--> Handler
  |
  v
Response

versus:

Warm invocation
----------------
Request
  |
  +--> Handler
  |
  v
Response

The benchmark should measure these separately.

What Changes With Durable Workflows?

A durable Lambda function is still a Lambda function, but the execution model adds checkpointing and replay.

AWS describes durable functions as using checkpoints to record workflow progress. When execution resumes, the function can replay from the beginning while skipping already-completed operations using their stored results.

The conceptual flow becomes:

Invocation
    |
    v
Step 1
    |
    v
Checkpoint
    |
    v
Step 2
    |
    v
Checkpoint
    |
    v
Wait
    |
    v
Invocation ends
    |
    ...
    |
    v
Resume
    |
    v
Replay
    |
    v
Continue from checkpoint

This means a durable workflow can have multiple Lambda invocations over its lifetime.

Consequently, measuring only the first invocation does not tell the whole performance story.

The Benchmarking Question

A useful benchmark should answer several questions:

  1. How long does a cold durable invocation take?

  2. How long does a warm invocation take?

  3. How much initialization time comes from the .NET application?

  4. Does workflow configuration materially affect startup?

  5. How much latency is introduced when a workflow resumes?

  6. How does deployment package size affect initialization?

  7. Does Native AOT change startup behavior?

  8. How does memory configuration affect latency?

  9. How does concurrency change cold-start frequency?

  10. What portion of total workflow latency comes from cold starts versus business operations?

The goal is to separate these variables instead of producing one misleading benchmark number.

Benchmark Standard Lambda and Durable Lambda Separately

Start with two functions:

Function A
-----------
Standard .NET Lambda
Simple handler


Function B
-----------
Durable .NET Lambda
Equivalent business logic

The business operation should be as similar as possible.

For example:

Input
  |
  v
Validate
  |
  v
Calculate
  |
  v
Return

Then create a durable version:

Input
  |
  v
Durable Step: Validate
  |
  v
Durable Step: Calculate
  |
  v
Return

This comparison does not prove that one architecture is universally faster.

It tells you what overhead exists for your particular implementation.

Measure More Than End-to-End Latency

A single number such as:

Duration = 850 ms

does not explain the result.

Capture at least:

Request timestamp
Initialization duration
Handler duration
Total duration
Cold/warm classification
Memory configuration
Runtime version
Package size
Concurrency
Workflow step count

For durable workflows, also record:

Checkpoint operations
Replay events
Wait duration
Resume latency
Retry count

The benchmark should make it possible to distinguish:

Runtime startup
+
Application initialization
+
Durable execution overhead
+
Business logic
+
External service latency

Use a Repeatable Benchmark

A practical test matrix could be:

VariableValues
Function typeStandard / Durable
MemorySeveral selected configurations
DeploymentZIP / container where relevant
CompilationJIT / Native AOT where supported
Workflow1 / 3 / 5 steps
InvocationCold / Warm
ConcurrencyLow / Medium / High
External callsNone / Controlled dependency

Do not change multiple variables without recording them.

For example, comparing:

Standard .NET 8
256 MB
ZIP

against:

Durable .NET
1024 MB
Container
Native AOT

does not isolate durable execution overhead.

Build a Minimal .NET Function First

Start with the smallest possible handler.

public class Function
{
    public string FunctionHandler(string input)
    {
        return $"Processed: {input}";
    }
}

This gives you a baseline for runtime and application initialization.

Then gradually add:

AWS SDK
Dependency Injection
Configuration
Logging
Database client
HTTP client
Business services
Durable SDK

Measure after each significant change.

This helps identify which dependencies are responsible for startup overhead.

Static Initialization Matters

.NET Lambda applications often initialize dependencies before the handler executes.

For example:

public class Function
{
    private static readonly AmazonDynamoDBClient Client =
        new();

    public async Task<string> FunctionHandler(
        string id)
    {
        // Business logic
        return await Task.FromResult(id);
    }
}

The static initialization can become part of startup work.

AWS recommends optimizing static initialization because imports, libraries, configuration, and connection setup can contribute to Lambda initialization latency.

The benchmark should therefore distinguish:

Runtime Initialization
+
Static Application Initialization

from:

Handler Execution

Benchmark Deployment Package Size

Package size can affect initialization behavior.

Create controlled versions:

Version A
---------
Minimal dependencies


Version B
---------
AWS SDK + application libraries


Version C
---------
Full production dependency set

Do not optimize package size blindly.

The goal is to determine whether a dependency materially affects your application's startup path.

A useful experiment is:

Package Size
     |
     v
Cold Start

rather than:

Package Size
     |
     v
Assumed Performance

Measure the relationship.

Benchmark Memory Configuration

Lambda allocates more CPU capacity as memory configuration increases.

Therefore, test several memory settings rather than assuming that the lowest memory value is the cheapest overall configuration.

For example:

MemoryCold p50Warm p50p95Cost/Invocation
Configuration AMeasureMeasureMeasureMeasure
Configuration BMeasureMeasureMeasureMeasure
Configuration CMeasureMeasureMeasureMeasure
Configuration DMeasureMeasureMeasureMeasure

The actual values should come from your workload.

The useful question is:

Where is the latency/cost trade-off for this application?

AWS recommends performance testing for .NET Lambda workloads because application behavior and initialization characteristics vary.

Benchmark Native AOT

For .NET applications where startup latency matters, Native AOT is an important comparison.

AWS documents that .NET 8 Lambda functions can be compiled using Native AOT and that this can reduce cold-start time by removing runtime compilation work.

Create two otherwise equivalent builds:

Build A
-------
Regular .NET deployment


Build B
-------
Native AOT

Measure:

Cold initialization
Warm invocation
Package characteristics
Memory behavior
Function correctness

Do not assume Native AOT will always be the best choice.

It can introduce compatibility and trimming considerations, so functional testing is required alongside performance testing.

Benchmark SnapStart Where Applicable

AWS Lambda SnapStart is another startup optimization available for supported runtimes, including .NET. AWS describes SnapStart as restoring an initialized execution environment from an encrypted snapshot instead of performing the full initialization sequence for each new environment.

For .NET, AWS also documents runtime hooks that can be used to perform initialization before snapshot creation.

A broader experiment can therefore compare:

Standard
   |
   +--> Cold Start


Native AOT
   |
   +--> Cold Start


SnapStart
   |
   +--> Restore Latency

The benchmark should verify which optimizations are supported by the exact runtime and durable-function configuration being evaluated before drawing conclusions.

Durable Workflow Benchmark

Now introduce a durable workflow.

Conceptually:

Input
 |
 v
Step 1: Validate
 |
 v
Step 2: Process
 |
 v
Step 3: Persist
 |
 v
Result

Each durable step becomes a checkpointed unit of work.

AWS documents that a step checkpoints its result and that replay can use the stored result rather than executing the completed step again. This is also why non-deterministic operations should generally be placed inside steps.

The benchmark should measure:

Initial invocation
+
Step execution
+
Checkpointing
+
Resume invocation
+
Replay
+
Final completion

Why Step Count Matters

Compare:

Workflow A
-----------
1 durable step

with:

Workflow B
-----------
3 durable steps

and:

Workflow C
-----------
5 durable steps

This helps identify how workflow granularity affects total execution behavior.

A simple table:

WorkflowStepsCold StartTotal DurationCheckpoints
A1MeasureMeasureMeasure
B3MeasureMeasureMeasure
C5MeasureMeasureMeasure

Do not conclude that fewer steps are automatically better.

Durable steps provide fault-isolation, retry, and checkpoint boundaries.

The correct granularity depends on the workflow.

Cold Start Versus Replay

A durable workflow may resume after a wait or interruption.

For example:

Invocation 1
    |
    v
Step A
    |
    v
Checkpoint
    |
    v
Wait
    |
    v
Invocation ends


Invocation 2
    |
    v
Replay
    |
    v
Step B
    |
    v
Result

AWS describes this replay behavior as part of the durable execution model.

This means a benchmark should not label every resumed invocation simply as a "cold start."

Instead, classify events:

Initial Cold
Warm Continuation
Resume After Wait
Resume After Failure
New Execution Environment

These represent different performance scenarios.

Benchmark Durable Waits

A normal sleep keeps the invocation alive.

A durable wait does not.

AWS documents that durable wait suspends the function after checkpointing and resumes it later without consuming Lambda compute during the wait.

For example, conceptually:

await context.WaitAsync(
    TimeSpan.FromMinutes(10));

The exact API should follow the version of the .NET SDK being used.

The important benchmark is:

Traditional sleep
vs
Durable wait

Measure:

Compute time
Resume latency
Total elapsed time

Do not compare only wall-clock duration.

A ten-minute workflow that spends ten minutes waiting is not equivalent to a ten-minute workflow consuming ten minutes of Lambda compute.

Benchmark External Service Calls

A realistic workflow may call:

Lambda
 |
 +--> DynamoDB
 |
 +--> S3
 |
 +--> HTTP API
 |
 +--> Payment Provider

External calls can dominate total latency.

Start with deterministic local computation:

No network

Then add:

DynamoDB

Then:

HTTP API

This lets you identify whether the observed latency comes from Lambda initialization or downstream dependencies.

Use Controlled External Latency

If you want to test workflow behavior under predictable conditions, use a controlled test dependency.

For example:

Test API
   |
   +--> 10 ms response
   +--> 100 ms response
   +--> 500 ms response

Then compare:

Workflow latency
vs
Dependency latency

This prevents a changing third-party service from contaminating the benchmark.

Benchmark Retries

Durable workflows support retry behavior for failed steps. AWS documents configurable retry strategies for durable steps.

A test can intentionally fail a step:

Attempt 1 -> Failure
Attempt 2 -> Failure
Attempt 3 -> Success

Measure:

Retry delay
Total workflow duration
Checkpoint behavior
Compute consumed
Final outcome

This is particularly important for workflows interacting with unreliable external services.

A retry benchmark should also verify that the business operation is safe to repeat according to the chosen execution semantics.

Test Idempotency

Durability does not automatically make an external side effect idempotent.

Consider:

ChargePayment()

If the operation is retried incorrectly, you could create duplicate business effects.

Prefer an idempotency key:

var request = new PaymentRequest
{
    OrderId = orderId,
    IdempotencyKey = executionId
};

The exact implementation depends on the external service.

The benchmark should verify:

Failure
  |
  v
Retry
  |
  v
Exactly one intended business effect

This is a functional correctness test as much as a performance test.

Measure Concurrency

Cold starts become more visible during bursts.

Run workloads such as:

1 request
10 requests
50 requests
100 requests
500 requests

These values are benchmark points, not claims about Lambda's capacity.

For each level, record:

Cold invocations
Warm invocations
p50 latency
p95 latency
p99 latency
Errors
Duration

A useful observation might look like:

Concurrency increases
        |
        v
More execution environments
        |
        v
More initialization events
        |
        v
Cold-start contribution increases

The actual relationship should be measured.

Use Percentiles Instead of Only Averages

Suppose your invocation durations are:

100 ms
110 ms
120 ms
130 ms
950 ms

The average is affected heavily by the outlier.

For latency-sensitive workloads, report:

p50
p90
p95
p99

For example:

MetricValue
p50Measure
p90Measure
p95Measure
p99Measure
MaximumMeasure

This makes cold-start outliers easier to understand.

CloudWatch Measurements

Lambda exposes execution information through CloudWatch.

A practical measurement pipeline is:

Lambda
 |
 v
CloudWatch Logs
 |
 v
Metrics
 |
 v
Benchmark Dataset
 |
 v
Analysis

Capture:

Duration
Errors
Throttles
Invocations

Then correlate these with your own application measurements.

For durable workflows, also inspect durable execution information and checkpoint behavior. AWS documents monitoring durable executions through the Lambda console and CloudWatch Logs.

Add Application-Level Timing

Cloud metrics alone are not enough.

Instrument the handler:

var stopwatch = Stopwatch.StartNew();

logger.LogInformation(
    "Workflow started at {Timestamp}",
    DateTimeOffset.UtcNow);

// Business logic

stopwatch.Stop();

logger.LogInformation(
    "Workflow completed in {ElapsedMs} ms",
    stopwatch.Elapsed.TotalMilliseconds);

For production systems, structured logs are preferable to string-only messages.

Record a correlation identifier:

ExecutionId
WorkflowId
RequestId
StepName

This makes individual executions easier to reconstruct.

Avoid Timing Non-Deterministic Operations Outside Steps

Durable workflows replay code.

AWS specifically recommends wrapping non-deterministic operations inside durable steps. Examples include retrieving the current time, generating random identifiers, performing external API calls, and producing other side effects.

For example, avoid putting arbitrary external work directly into replayed orchestration logic.

Instead:

Durable Workflow
      |
      v
Durable Step
      |
      v
External API

The step's result can then be checkpointed and reused during replay.

This is important for both correctness and benchmark interpretation.

Benchmark Package and Initialization Optimization

For .NET Lambda, examine:

Package size
Dependency count
Reflection
JSON serialization
Static initialization
DI registration
AWS SDK clients
Configuration loading

AWS recommends source generators and Native AOT among the techniques that can improve .NET Lambda startup behavior.

A good optimization sequence is:

Baseline
   |
   v
Measure
   |
   v
Remove unnecessary initialization
   |
   v
Measure
   |
   v
Optimize serialization
   |
   v
Measure
   |
   v
Evaluate Native AOT / SnapStart
   |
   v
Measure Again

Do not optimize based on assumptions.

Durable SDK Versioning

The AWS Lambda Durable Execution SDK for .NET became generally available in July 2026. AWS's announcement states that the SDK is distributed through NuGet and includes local testing capabilities.

For production, pin the SDK version rather than allowing an uncontrolled dependency update.

This is particularly important for durable workflows because executions may span multiple invocations.

AWS recommends versioning and qualifying durable functions because durable executions require qualified function ARNs and because dependency/runtime changes can affect in-flight executions.

Production Deployment Considerations

Durable functions cannot simply be treated as ordinary Lambda functions.

AWS requires durable execution to be enabled when the function is created, and infrastructure-as-code deployments require the necessary checkpoint permissions. Durable functions also require qualified ARNs using a version or alias.

A production deployment should therefore include:

Source
  |
  v
Build
  |
  v
Test
  |
  v
Publish Version
  |
  v
Alias
  |
  v
Durable Function

Avoid relying on:

$LATEST

for production durable execution management.

Standard Lambda vs Durable Lambda

CharacteristicStandard LambdaDurable Lambda
Basic executionSingle invocationDurable execution
CheckpointingApplication-managedBuilt-in durable operations
Long waitsInvocation remains activeFunction can suspend
State recoveryApplication-managedCheckpoint/replay
RetriesApplication/service dependentDurable step retry support
ReplayNo orchestration replay modelYes
Maximum workflow durationStandard Lambda limitsUp to one year
Best suited forShort event-driven workMulti-step resilient workflows

AWS documents durable functions as supporting workflows that can execute for up to one year, while standard Lambda functions remain subject to their normal execution model.

Durable Functions vs Step Functions

Durable Lambda does not replace every workflow engine.

AWS positions durable functions and Step Functions differently.

Durable functions are oriented toward application logic written inside Lambda, while Step Functions is designed for workflow orchestration across AWS services and provides a visual workflow model with extensive service integrations.

A practical decision looks like:

RequirementDurable FunctionsStep Functions
Workflow logic primarily in codeStrong fitPossible
Lambda-centric applicationStrong fitPossible
Visual workflow definitionLimitedStrong
Cross-service orchestrationGoodStrong
Fine-grained code-level controlStrongDifferent model
Long-running workflowsYesYes
Existing Step Functions estateMigration may not be justifiedStrong fit

The benchmark should therefore evaluate the architecture against the application's requirements, not just raw latency.

A Practical Benchmark Harness

A simple C# benchmark runner can invoke a function repeatedly and capture elapsed time:

var stopwatch = Stopwatch.StartNew();

var response = await lambdaClient.InvokeAsync(
    new InvokeRequest
    {
        FunctionName = functionName,
        InvocationType = InvocationType.RequestResponse,
        Payload = payload
    });

stopwatch.Stop();

Console.WriteLine(
    $"Status={response.StatusCode}, " +
    $"Elapsed={stopwatch.Elapsed.TotalMilliseconds:F2} ms");

For a serious benchmark, extend this to record:

Iteration
Concurrency
Cold/Warm classification
Status
Duration
Payload size
Workflow ID
Error

Store the results as structured data rather than relying on console output.

Example Benchmark Dataset

Your final dataset might look like:

RunTypeConcurrencyColdStepsDuration
1Standard1YesN/AMeasure
2Standard1NoN/AMeasure
3Durable1Yes1Measure
4Durable1No1Measure
5Durable1Yes3Measure
6Durable10Mixed3Measure

Run enough iterations to reduce the influence of individual outliers.

Do not publish a benchmark from five requests and call it a production performance study.

Common Benchmarking Mistakes

Comparing Different Applications

If the standard Lambda and durable Lambda perform different work, the comparison is weak.

Measuring Only the First Request

One cold invocation does not represent normal workflow behavior.

Ignoring Replay

Durable workflows can resume and replay, so the complete execution lifecycle matters.

Using Real External Services Without Controls

Changing downstream latency can dominate the results.

Reporting Only Average Latency

Percentiles reveal outliers much better.

Changing Memory Between Tests

That changes CPU allocation and makes attribution difficult.

Mixing AOT, SnapStart, and JIT Without Labeling Them

These are different deployment configurations.

Ignoring Workflow Granularity

One large step and ten small steps have different checkpoint behavior.

Putting Side Effects Outside Durable Steps

Replay can cause unexpected behavior if non-deterministic or side-effecting operations are not modeled correctly.

Troubleshooting Unexpected Cold Starts

Warm Requests Are Still Slow

Check:

  • Static initialization

  • Dependency loading

  • Network initialization

  • Database clients

  • Configuration loading

  • Function memory

  • Downstream services

Cold Starts Increase During Bursts

Check concurrency and the number of new execution environments being created.

Also distinguish cold-start latency from downstream service latency.

Native AOT Does Not Improve the Result

Check:

  • Whether initialization was actually the bottleneck

  • AOT compatibility

  • Deployment configuration

  • Dependency behavior

  • Measurement methodology

AOT is an optimization, not a guarantee of a particular latency improvement.

Durable Workflow Takes Longer After a Wait

That is expected to some extent because resumption involves another invocation and replay.

Measure:

Wait completion
+
Resume scheduling
+
Initialization if needed
+
Replay
+
Remaining steps

AWS notes that actual resume timing can depend on system scheduling, Lambda cold-start behavior, and current system load.

Retry Causes Unexpected Duplicate Work

Check whether the operation is idempotent and whether side effects are correctly encapsulated within durable steps.

Best Practices

  1. Benchmark standard and durable functions separately.

  2. Measure cold and warm invocations independently.

  3. Record p50, p95, and p99 latency.

  4. Keep workload and configuration consistent between comparisons.

  5. Measure initialization separately from business logic.

  6. Test multiple memory configurations.

  7. Evaluate deployment package size and initialization dependencies.

  8. Benchmark Native AOT when appropriate for the .NET workload.

  9. Evaluate SnapStart where supported by the selected configuration.

  10. Measure workflow resume and replay behavior.

  11. Test different durable-step granularities.

  12. Keep external dependencies controlled during infrastructure benchmarks.

  13. Make external side effects idempotent.

  14. Use structured logging and execution correlation IDs.

  15. Pin production SDK versions.

  16. Deploy durable functions using qualified versions or aliases.

  17. Repeat benchmarks under realistic concurrency.

  18. Do not publish unsupported universal cold-start claims.

Conclusion

Durable Lambda changes the question developers should ask about serverless performance.

For a conventional Lambda function, the primary concern may be:

How fast can this request start and finish?

For a durable workflow, the question becomes:

How efficiently does this workflow move
through initialization, steps, checkpoints,
waits, retries, replay, and completion?

AWS Lambda's durable execution model provides checkpointing, replay, retries, waits, callbacks, parallel operations, and durable invocation while allowing workflows to run for up to one year.

The .NET SDK is now generally available, giving C# developers an idiomatic way to build these workflows.

But durable execution introduces additional dimensions that need to be measured.

A serious benchmark should therefore separate:

Cold Start
     +
Application Initialization
     +
Durable Checkpointing
     +
Business Logic
     +
External Services
     +
Replay
     +
Resume

Do not reduce all of that to a single latency number.

For production .NET workloads, benchmark the actual application, use controlled workloads, test realistic concurrency, compare deployment strategies, and measure both performance and correctness.

The most useful result is not:

"Durable Lambda adds X milliseconds."

It is:

"For this workload, this workflow structure, this .NET configuration, and this concurrency profile, cold starts represent this portion of total latency, while durable execution provides these reliability benefits."

That is a benchmark that can actually inform an architecture decision.

Frequently Asked Questions

What is a cold start in AWS Lambda?

A cold start occurs when Lambda creates and initializes a new execution environment before running the function. Initialization can include runtime startup, code loading, and application initialization.

Does a durable workflow eliminate cold starts?

No. Durable functions still use Lambda execution environments. A workflow can involve multiple invocations, and a resumed execution can require initialization depending on the execution environment lifecycle.

How long can a durable Lambda workflow run?

AWS currently documents durable workflows with execution durations of up to one year. Wait operations can suspend execution without consuming Lambda compute during the wait.

Does a durable wait consume Lambda compute?

No. A durable wait checkpoints the operation, suspends the function, and resumes it later when the wait completes.

Should I use Native AOT for .NET Lambda?

It is worth benchmarking when startup latency matters. AWS documents Native AOT as a way to reduce .NET Lambda cold-start work, but compatibility and application characteristics still need to be evaluated.

Should I use Step Functions instead of durable Lambda?

Not automatically. AWS positions durable functions as a code-centric workflow model inside Lambda, while Step Functions is a broader workflow orchestration service. The appropriate choice depends on the application's architecture and operational requirements.

What is the most important metric for this benchmark?

There is no single metric. For latency-sensitive applications, start with cold-start p50/p95/p99, warm latency, and total workflow duration. For durable workflows, also measure resume latency, replay behavior, retries, and checkpoint-related behavior.

Is the .NET Durable Execution SDK production-ready?

AWS announced general availability of the AWS Lambda Durable Execution SDK for .NET on July 23, 2026.