AI workflows are becoming more structured.
A production agent may need to perform several steps:
User Request
|
v
Triage Agent
|
v
Specialist Agent
|
v
Business Rule
|
v
Human Approval
|
v
Final Action
Traditionally, developers implement this orchestration directly in application code.
Microsoft Agent Framework now provides another approach: Declarative Workflows, where workflow orchestration is described using YAML instead of being constructed entirely through programmatic APIs. Declarative Workflows reached version 1.0 across the Microsoft Agent Framework SDKs in July 2026, with the .NET declarative workflow package already stable.
This raises an important engineering question:
Does moving workflow definitions from C# code into YAML affect runtime performance?
The answer requires some nuance.
Declarative and code-first workflows ultimately execute through the same Workflow abstraction. Microsoft explicitly states that a declarative definition loads into a standard workflow that can be run, streamed, and composed like a code-first workflow.
Therefore, the most useful comparison is not simply:
YAML = slower
C# = faster
Instead, teams should measure several distinct costs:
Definition Loading
+
Workflow Construction
+
Execution Overhead
+
Agent/API Latency
+
Maintenance Cost
+
Deployment Flexibility
What Is a Declarative AI Workflow?
A declarative workflow describes what the workflow should do rather than implementing the orchestration entirely through application code.
A simplified C# declarative workflow definition looks like:
kind: Workflow
trigger:
kind: OnConversationStart
id: support_router
actions:
- kind: InvokeAzureAgent
id: triage
displayName: Triage request
- kind: InvokeAzureAgent
id: specialist
displayName: Handle request
The YAML describes the workflow structure.
The framework loads that definition and converts it into an executable workflow.
Microsoft describes this approach as defining workflow logic through YAML configuration rather than programmatic code.
What Is a Code-First Workflow?
A code-first workflow defines the workflow topology directly in application code.
For example:
using Microsoft.Agents.AI.Workflows;
var processor = new DataProcessor();
var validator = new Validator();
var formatter = new Formatter();
WorkflowBuilder builder =
new(processor);
builder.AddEdge(processor, validator);
builder.AddEdge(validator, formatter);
Workflow workflow =
builder.Build();
This approach gives the developer direct control over workflow construction.
Microsoft's WorkflowBuilder API is designed for constructing workflows from executors and edges.
The two approaches can therefore be represented as:
Declarative
YAML
|
v
Declarative Builder
|
v
Workflow
|
v
Execution
and:
Code-First
C#
|
v
WorkflowBuilder
|
v
Workflow
|
v
Execution
The important observation is that both ultimately produce a Workflow.
YAML vs Code: The Architectural Difference
The biggest difference is not necessarily runtime execution.
It is where the workflow definition lives.
| Area | Declarative YAML | Code-First C# |
|---|
| Workflow definition | YAML | C# |
| Type safety | More limited | Strong |
| Runtime flexibility | Structured | High |
| Custom logic | Limited by supported actions | Very flexible |
| Version control | Excellent | Excellent |
| Non-developer readability | Higher | Lower |
| Compile-time validation | More limited | Stronger |
| Standard orchestration | Excellent | Excellent |
| Complex custom logic | Less suitable | Better |
| Dynamic programmatic behavior | Limited | Strong |
| Runtime model | Standard Workflow | Standard Workflow |
Microsoft's documentation recommends declarative workflows for standard orchestration patterns and frequently changing workflows, while programmatic workflows are more appropriate when complex custom logic or maximum control is required.
Does YAML Add Runtime Overhead?
There are actually two different operations to consider.
Workflow Construction
The application must parse and build the YAML definition.
Conceptually:
YAML
|
v
Parse
|
v
Validate
|
v
Build Workflow
Code-first workflows instead construct the workflow directly from C# objects.
Therefore, there can be a cost associated with loading a declarative workflow.
But that cost should not automatically be confused with the cost of every workflow execution.
Workflow Execution
After the declarative definition has been loaded into a Workflow, the framework executes that workflow through the normal workflow runtime.
Microsoft explicitly states that declarative workflows load as standard Workflow instances and can be run, streamed, and composed like code-first workflows.
This distinction is critical.
Separate Build Time From Runtime
A useful benchmark should measure:
Phase 1
YAML Loading
|
v
Workflow Construction
separately from:
Phase 2
Workflow Execution
Otherwise, a one-time workflow construction cost can be incorrectly reported as an execution penalty.
For example:
Application Startup
|
+-- Load YAML
+-- Build Workflow
|
v
Workflow Ready
|
+-- Request 1
+-- Request 2
+-- Request 3
+-- ...
If the workflow is built once and reused, the YAML parsing cost is amortized across requests.
The Most Important Benchmark Question
Instead of asking:
"Is YAML faster than C#?"
ask:
"What percentage of total application latency is attributable to workflow definition loading and orchestration overhead?"
This is a much more useful production question.
An AI workflow may contain:
YAML Loading
2 ms
|
v
Workflow Execution
20 ms
|
v
LLM Request
900 ms
|
v
External API
200 ms
In this hypothetical architecture, optimizing YAML parsing would have a very different impact than optimizing the model or external API calls.
The actual values must be measured rather than assumed.
LLM Latency Changes the Equation
AI workflows frequently call external model APIs.
For example:
Workflow
|
v
Agent
|
v
Network
|
v
Model
|
v
Response
The model request can dominate end-to-end latency.
A workflow-level microbenchmark might therefore show a difference that is practically insignificant in a real application.
This is why performance testing should have at least two layers:
Microbenchmark
|
v
Workflow Engine Cost
End-to-End Benchmark
|
v
Workflow + Model + Tools + Network
Both answer different questions.
Build a Minimal Benchmark
Start with a workflow that does not call an external model.
For example, create a simple executor:
public sealed class Processor
{
public string Process(string input)
{
return input.ToUpperInvariant();
}
}
Then create an equivalent code-first workflow.
For the declarative version, define the corresponding action in YAML.
The objective is to isolate:
Workflow Construction
+
Workflow Execution
from:
LLM
+
Network
+
Database
Benchmark Workflow Construction
A benchmark should separately measure how long it takes to create the workflow.
Conceptually:
[Benchmark]
public Workflow BuildWorkflow()
{
return DeclarativeWorkflowBuilder.Build<string>(
_workflowPath,
_options);
}
The code-first equivalent can measure:
[Benchmark]
public Workflow BuildCodeWorkflow()
{
var processor = new Processor();
var validator = new Validator();
var builder =
new WorkflowBuilder(processor);
builder.AddEdge(processor, validator);
return builder.Build();
}
The exact generic types and executor implementation depend on the workflow being tested.
The important principle is to benchmark equivalent workflow graphs.
Benchmark Execution Separately
Once the workflow has been built:
Build
|
v
Workflow Instance
|
+---- Execution 1
+---- Execution 2
+---- Execution 3
Benchmark execution without rebuilding the workflow every time.
Otherwise, the benchmark answers:
Build + Execute
instead of:
Execute
This distinction is particularly important for declarative workflows.
Avoid This Benchmark
Do not benchmark:
[Benchmark]
public async Task Execute()
{
var workflow =
DeclarativeWorkflowBuilder.Build<string>(
"workflow.yaml",
_options);
await workflow.RunAsync(...);
}
if the production application actually builds the workflow only once.
That test repeatedly includes workflow construction.
Instead:
private Workflow _workflow;
[GlobalSetup]
public void Setup()
{
_workflow =
DeclarativeWorkflowBuilder.Build<string>(
"workflow.yaml",
_options);
}
[Benchmark]
public async Task Execute()
{
await _workflow.RunAsync(...);
}
The exact execution API depends on the workflow and framework version.
The benchmark design is the important part.
Benchmark the Same Workflow Graph
The YAML and C# implementations should represent the same logical graph.
For example:
+----------+
| Triage |
+----+-----+
|
+----v-----+
| Validate |
+----+-----+
|
+----v-----+
| Respond |
+----------+
Do not compare:
YAML
3 actions
against:
C#
10 actions
and then attribute the difference to the authoring model.
Control the workflow topology.
Benchmark Sequential Workflows
Start with a sequential workflow:
A
|
v
B
|
v
C
Measure:
Construction
Execution
Memory
Allocations
Then expand the experiment.
Benchmark Parallel Workflows
Agent Framework workflows can model parallel execution.
Conceptually:
+--> Agent A --+
| |
Input -+ +--> Merge
| |
+--> Agent B --+
The framework supports graph-based workflow execution with parallel processing and other control-flow patterns.
For a parallel benchmark, measure:
Total Execution Time
CPU Utilization
Task Scheduling
Memory
Synchronization
Do not assume YAML or C# changes the performance of the underlying parallel operations simply because the workflow was authored differently.
Benchmark Conditional Routing
A conditional workflow might look like:
Input
|
v
Classifier
|
+---- Billing ---> Billing Agent
|
+---- Sales -----> Sales Agent
|
+---- Support ---> Support Agent
Declarative workflows support conditional routing and other control-flow actions.
Benchmark:
Routing Time
+
Selected Branch Execution
The routing decision may involve an LLM.
If so, separate model latency from workflow-engine overhead.
Benchmark Human-in-the-Loop Workflows
Declarative workflows also support human-in-the-loop scenarios.
For example:
Agent
|
v
Risk Check
|
v
Approval
|
+---- Reject
|
+---- Approve
|
v
Action
Human waiting time should not be treated as workflow execution latency.
Instead, measure:
Workflow Processing Time
and separately:
Human Wait Time
This is especially important when analyzing production SLAs.
YAML Expression Evaluation
Declarative workflows use an expression language for dynamic values.
For example:
- kind: SetVariable
variable: Local.message
value: =Concat(
"Hello, ",
System.LastMessage.Text
)
Microsoft documents Power Fx-based expressions for declarative workflows.
This creates another potential benchmark dimension:
Expression Parsing
Expression Evaluation
Variable Resolution
For most workflows, these operations should be measured independently from external model and network calls.
Code Has Different Performance Characteristics
Code-first workflows can execute arbitrary C# logic directly.
For example:
if (customer.IsPremium)
{
await premiumProcessor.ProcessAsync(customer);
}
else
{
await standardProcessor.ProcessAsync(customer);
}
This provides direct access to:
If a workflow requires substantial custom computation, code-first orchestration can be a better fit.
YAML Has Different Operational Characteristics
Declarative YAML is particularly attractive when the workflow structure changes independently from application implementation.
For example:
Product Owner
|
v
Workflow Definition
|
v
YAML Review
|
v
Version Control
|
v
Deployment
A change to a routing rule or agent handoff can often be expressed as a workflow-definition change instead of modifying the orchestration code.
Microsoft highlights reviewability, versioning, and the ability to change orchestration separately from application logic as key benefits of declarative workflows.
Compare Startup Behavior
Declarative workflows may need to load their YAML definition.
Therefore, if an application creates workflows during startup:
Application Start
|
v
Load YAML
|
v
Build Workflow
|
v
Application Ready
measure startup impact.
For a long-running service, this may be a small one-time cost.
For a short-lived process:
Start
|
v
Load Workflow
|
v
Execute Once
|
v
Exit
the cost may become more relevant.
The workload determines the significance.
Cache or Reuse Workflows
If the workflow definition does not change per request, avoid rebuilding it unnecessarily.
Prefer:
Application Startup
|
v
Build Workflow
|
v
Reuse
|
+--> Request 1
+--> Request 2
+--> Request 3
rather than:
Request 1
|
v
Build Workflow
|
v
Execute
Request 2
|
v
Build Workflow
|
v
Execute
The exact lifecycle should follow the framework's threading and state-management requirements.
Do not share mutable workflow state across concurrent requests unless the API guarantees that it is safe.
Version Control Is a Major Advantage of YAML
A declarative workflow can be reviewed like a configuration artifact:
support-workflow.yaml
A change might look conceptually like:
- id: billing_agent
+ id: finance_agent
The orchestration change is immediately visible.
This can make architectural review easier.
Code-first workflows also work well with Git, but the workflow structure may be mixed with implementation details.
YAML Improves Separation of Concerns
A clean architecture can separate:
Business Logic
|
v
Services / Tools
|
v
Workflow Definition
|
v
Agents
The workflow determines how components interact.
The components determine how individual operations are implemented.
This separation can reduce the amount of orchestration logic embedded directly in application classes.
Code Provides Stronger Compile-Time Guarantees
One of the major advantages of code-first workflows is the compiler.
For example:
WorkflowBuilder builder =
new WorkflowBuilder(processor);
builder.AddEdge(
processor,
validator);
Types and method signatures can be validated during compilation.
With YAML, many problems can only be discovered during workflow loading or execution.
Therefore:
C#
|
v
Compile-Time Validation
versus:
YAML
|
v
Load-Time / Runtime Validation
is an important engineering trade-off.
YAML Validation in CI
This does not mean YAML should be edited without validation.
A production pipeline should validate:
YAML Syntax
Workflow Schema
Referenced Agents
Referenced Tools
Expressions
Required Configuration
Security Policies
before deployment.
A useful pipeline is:
Pull Request
|
v
YAML Validation
|
v
Workflow Tests
|
v
Security Checks
|
v
Integration Tests
|
v
Deploy
Test Declarative Workflows Like Code
Even though the workflow is stored in YAML, it is still executable behavior.
Test:
Happy Path
Invalid Input
Branching
Agent Failure
Tool Failure
Timeout
Approval Rejection
External API Failure
Workflow Resume
A workflow definition should not be considered safe simply because it is configuration.
Performance Metrics to Collect
A useful comparison should collect:
| Metric | Why It Matters |
|---|
| YAML load time | Measures definition parsing |
| Workflow build time | Measures construction |
| Execution time | Measures workflow runtime |
| Allocations | Measures memory pressure |
| Peak memory | Measures resource usage |
| Startup impact | Measures application initialization |
| First execution | Detects initialization effects |
| Subsequent execution | Measures steady state |
| End-to-end latency | Measures real application behavior |
For AI workloads, also measure:
Model latency
Token usage
Tool latency
Network latency
External API latency
These often dominate the total request time.
Use BenchmarkDotNet for Microbenchmarks
A dedicated benchmark project is useful.
Create one:
dotnet new console -n WorkflowBenchmarks
cd WorkflowBenchmarks
dotnet add package BenchmarkDotNet
Then:
using BenchmarkDotNet.Attributes;
[MemoryDiagnoser]
public class WorkflowBenchmark
{
[Benchmark]
public void BuildCodeWorkflow()
{
// Build equivalent code-first workflow.
}
[Benchmark]
public void BuildDeclarativeWorkflow()
{
// Load equivalent YAML workflow.
}
}
The benchmark should be expanded with real workflow construction and execution.
The important point is to keep construction and execution as separate benchmark methods.
Measure Allocations
Add:
[MemoryDiagnoser]
This can help identify whether one workflow-definition approach creates additional allocations during construction.
For example:
Build YAML
|
+-- Parse YAML
+-- Create objects
+-- Build graph
versus:
Build C#
|
+-- Create objects
+-- Build graph
The actual allocation difference should be measured.
Do not assume one approach has lower allocation without evidence.
Benchmark Cold Start
A cold-start benchmark should include:
Process Start
|
v
Workflow Load
|
v
Workflow Build
|
v
Ready
Repeat it across multiple processes rather than repeatedly constructing the workflow inside one already-running process.
This provides a more realistic startup measurement.
Benchmark Warm Execution
A warm benchmark should look like:
Build Once
|
v
Execute
Execute
Execute
Execute
...
This isolates steady-state execution.
For a service that keeps its workflow alive for hours, warm execution is usually more representative of request processing.
Benchmark With and Without LLM Calls
Use two benchmark categories.
Engine Benchmark
Workflow
|
v
Local Executors
This isolates workflow-engine behavior.
End-to-End Benchmark
Workflow
|
v
Agent
|
v
LLM
|
v
Tools
|
v
External APIs
This represents application behavior.
Do not use one benchmark to answer both questions.
YAML vs Code Performance Matrix
A useful final comparison can look like this:
| Dimension | YAML | Code |
|---|
| Workflow construction | Measure | Measure |
| Warm execution | Measure | Measure |
| Cold startup | Measure | Measure |
| Allocations | Measure | Measure |
| Custom logic | Limited by declarative actions | Strong |
| Compile-time checking | Lower | Strong |
| Runtime model | Standard Workflow | Standard Workflow |
| Workflow review | Strong | Strong |
| Non-developer readability | Strong | Lower |
| Rapid orchestration changes | Strong | Requires code change |
| Maximum flexibility | Lower | Strong |
The table should be populated with actual benchmark results when publishing a performance study.
When YAML Is the Better Choice
Declarative workflows are a strong candidate when:
The workflow follows standard orchestration patterns.
The topology changes frequently.
Multiple teams review workflow behavior.
Workflow definitions benefit from configuration-style versioning.
Non-developers need to understand the orchestration.
Custom code is limited.
Microsoft's documentation explicitly recommends declarative workflows for standard orchestration and workflows that change frequently.
When Code Is the Better Choice
Use code-first workflows when:
Complex custom logic is required.
Strong compile-time typing is important.
The workflow dynamically constructs its topology.
Existing C# services need direct integration.
Specialized algorithms are part of the orchestration.
Maximum framework-level control is required.
Microsoft identifies complex custom logic and maximum flexibility as strong cases for programmatic workflows.
Hybrid Architecture
The choice does not need to be binary.
A production application can use:
Application
|
+-------+-------+
| |
v v
Declarative Code-First
Workflow Workflow
| |
+-------+-------+
|
v
Shared Components
Microsoft explicitly states that declarative workflows can be composed with code-first workflows because both become standard Workflow instances.
This is often the most practical architecture.
Example Hybrid Pattern
Use YAML for the high-level orchestration:
Triage
|
v
Classification
|
+---- Billing
+---- Sales
+---- Support
Then use C# for complex business logic:
public sealed class RefundEligibilityService
{
public bool IsEligible(Order order)
{
// Complex business rules.
return order.Status == OrderStatus.Completed;
}
}
The declarative workflow determines when the service is invoked.
The C# implementation determines how the business rule works.
Avoid Putting Business Logic in YAML
A common mistake is turning YAML into a programming language.
For example:
if:
condition: ...
# Hundreds of lines of business logic
This makes the workflow difficult to maintain.
Prefer:
YAML
|
v
Business Service
|
v
Result
Keep orchestration in YAML and complex business rules in code.
Avoid Putting Everything in C#
The opposite mistake is also common.
A developer may create a large orchestration class containing:
Routing
Agent selection
Approval
Retry
Timeout
Branching
Tool selection
When the workflow topology changes frequently, separating it into a declarative definition can make the architecture easier to review.
Failure Handling
Performance is not the only concern.
Compare how each approach handles failures.
A production workflow needs to consider:
Agent Failure
Tool Failure
Network Failure
Timeout
Invalid Output
Approval Rejection
Checkpoint Recovery
Agent Framework workflows support checkpointing and recovery for long-running processes.
The chosen authoring model should preserve the same operational requirements.
Checkpointing Considerations
Declarative workflows can also use workflow checkpointing.
The current documentation notes a specific consideration for Native AOT and trimming: JSON checkpoint serialization should use the provided DeclarativeWorkflowJsonOptions.Default source-generated options rather than relying on reflection-based serialization.
For example:
CheckpointManager checkpointManager =
CheckpointManager.CreateJson(
store,
DeclarativeWorkflowJsonOptions.Default);
This is a good example of why production architecture should consider more than workflow execution speed.
Deployment model and serialization behavior can also affect the implementation.
Common Mistakes
Comparing Different Workflows
Use equivalent graphs.
Measuring YAML Parsing as Runtime Execution
Separate construction from execution.
Rebuilding the Workflow Per Request
Reuse immutable or appropriately scoped workflow definitions where supported.
Including LLM Latency in an Engine Benchmark
Measure workflow overhead separately.
Assuming YAML Is Automatically Slower
The runtime model matters more than the source representation.
Assuming YAML Is Automatically Faster
Declarative authoring does not guarantee better runtime performance.
Ignoring Allocations
Measure memory behavior.
Ignoring Startup
For short-lived workloads, construction cost may matter more.
Ignoring Maintainability
A tiny theoretical performance difference may not justify significantly more complex orchestration code.
Putting Business Logic Into YAML
Keep complex domain logic in typed application code.
Troubleshooting
YAML Workflow Takes Too Long to Start
Measure:
File I/O
+
YAML Parsing
+
Workflow Construction
+
Agent Configuration
Do not assume the YAML parser is responsible for the complete startup delay.
Runtime Execution Is Slower
First determine whether the difference exists in:
Workflow Engine
or:
Agent / Tool / Network
Run a local-executor benchmark before testing a complete AI workflow.
YAML and C# Produce Different Results
Verify that:
The workflow graph is identical.
The same agents are used.
The same tools are registered.
The same configuration is loaded.
The same input is supplied.
The same model is used.
YAML Changes Break Production
Introduce CI validation and integration tests before deployment.
Treat workflow definitions as executable artifacts.
Developers Keep Adding Logic to YAML
Establish a boundary:
Orchestration -> YAML
Business Logic -> C#
When an expression becomes difficult to understand, move it into a typed service.
Best Practices
Benchmark workflow construction separately from execution.
Use identical workflow graphs when comparing YAML and C#.
Measure cold-start and warm-execution behavior separately.
Measure allocations and memory usage.
Keep LLM and external API latency separate from workflow-engine measurements.
Use declarative workflows for standard orchestration patterns.
Use code-first workflows for complex custom logic.
Use a hybrid architecture when both approaches provide value.
Keep business logic in typed application code.
Version YAML workflows in source control.
Validate YAML definitions in CI.
Test workflow failures and recovery paths.
Reuse workflow definitions when appropriate instead of rebuilding them per request.
Document the exact framework and package versions used for benchmarks.
Do not publish unsupported performance percentages.
Evaluate maintainability and deployment flexibility alongside raw performance.
Frequently Asked Questions
Is a YAML workflow slower than a C# workflow?
Not necessarily.
Declarative workflows have a definition-loading and construction phase, but once loaded they become standard Workflow instances. Microsoft explicitly states that declarative workflows can run, stream, and compose like code-first workflows.
Actual performance differences should be measured for the specific workflow.
Does YAML parsing happen on every workflow execution?
That depends on how the application manages the workflow lifecycle.
If the workflow is loaded once and reused, YAML parsing and construction are startup costs rather than per-request execution costs.
Which is better for production: YAML or C#?
Neither is universally better.
Use YAML when the workflow topology is standardized and benefits from independent review and iteration.
Use C# when complex custom logic and maximum control are more important.
Does declarative workflow improve AI model performance?
Not directly.
Changing the workflow authoring format does not inherently make the underlying language model faster or more accurate.
It can, however, improve workflow maintainability and make orchestration easier to modify.
Can YAML and code-first workflows be combined?
Yes.
Declarative definitions load into standard Workflow instances and can be run and composed with code-first workflows.
Should I use YAML for business rules?
Generally, keep complex business rules in application code.
Use YAML primarily to describe orchestration and workflow structure.
Does YAML provide compile-time type safety like C#?
No.
C# benefits from compiler-level type checking, while YAML workflow definitions are primarily validated when they are parsed, built, or executed.
This is one reason CI validation and workflow integration tests are important.
Is performance the main reason to choose between YAML and C#?
Usually not.
The more important factors are workflow complexity, change frequency, maintainability, type safety, custom logic, deployment model, and team ownership.
Conclusion
Declarative AI workflows change where orchestration logic lives.
Instead of embedding the entire workflow in C#:
C# Application
|
v
WorkflowBuilder
|
v
Workflow
developers can define the orchestration separately:
YAML
|
v
DeclarativeWorkflowBuilder
|
v
Workflow
The important point is that both approaches converge on the same workflow abstraction. Microsoft explicitly describes declarative workflows as standard Workflow instances that can be run, streamed, and composed with code-first workflows.
That means a simplistic claim such as:
"YAML workflows are slower than C# workflows."
is not an adequate engineering conclusion.
A better performance model is:
Workflow Performance
|
+--------------+--------------+
| | |
v v v
Construction Execution External Work
| | |
v v v
YAML/C# Framework LLM/API/DB
Benchmark these dimensions separately.
For most AI applications, external model and tool latency can dominate the request lifecycle, making small workflow-definition differences less significant than architectural decisions around model calls, network dependencies, and tool execution.
The practical decision is therefore:
Standard Orchestration
|
v
YAML
Complex Custom Logic
|
v
C#
Both Required
|
v
Hybrid
The strongest production strategy is not to choose YAML or C# based on an assumed performance advantage.
Choose the authoring model that matches the workflow's complexity and change rate, then benchmark construction, execution, memory, and end-to-end latency under the actual workload.
That approach provides measurable performance data without sacrificing the maintainability and flexibility that declarative AI workflows are designed to provide.