What is the difference between ConfigureAwait(false) and ConfigureAwait(true) ?
Question
What is the difference between ConfigureAwait(false) and ConfigureAwait(true) ?
Brief Answer
The ConfigureAwait method controls how the remainder of an asynchronous method (its “continuation”) behaves after an await operation completes, specifically regarding thread affinity.
ConfigureAwait(true) (Default Behavior)
- Captures Context: By default, it captures the current
SynchronizationContext(if one exists, common in UI apps) or the currentTaskScheduler. - Resumes on Original Thread: The continuation (code after
await) attempts to resume execution on the *original thread* that initiated theawait. - Primary Use Case: Essential for UI applications (WPF, Windows Forms, Blazor Client-Side) to ensure UI updates happen safely on the UI thread, preventing cross-thread exceptions.
- Potential Pitfall: Can lead to deadlocks if the original thread is blocked (e.g., by calling
.Resultor.Wait()) while waiting for the async operation to complete, and that operation needs to return to the original thread.
ConfigureAwait(false)
- Does NOT Capture Context: It explicitly instructs the runtime *not* to capture the current
SynchronizationContextorTaskScheduler. - Resumes on Any Thread: The continuation is free to resume on *any available thread pool thread*.
- Primary Use Case: Highly recommended for library code, general-purpose components, and server-side applications (like ASP.NET Core) where thread affinity isn’t required.
- Key Benefits:
- Performance: Reduces thread context switching overhead, improving efficiency and throughput in high-concurrency scenarios.
- Deadlock Prevention: Helps prevent deadlocks when library code is consumed by callers who might block the calling thread.
In essence: Use ConfigureAwait(true) (or implicitly default) when you *need* to return to a specific context (e.g., UI thread for UI updates). Use ConfigureAwait(false) when you *don’t care* about the context, prioritizing performance and avoiding deadlocks, especially in shared libraries or server-side code.
Super Brief Answer
ConfigureAwait controls whether the continuation of an await operation resumes on the original thread or any available thread.
ConfigureAwait(true)(Default): Captures the currentSynchronizationContextand ensures the continuation resumes on the *original thread*. This is crucial for UI applications to safely update UI elements, but can lead to deadlocks if the original thread is blocked.ConfigureAwait(false): Does *not* capture theSynchronizationContext, allowing the continuation to resume on *any available thread pool thread*. This improves performance by reducing context switching overhead and helps prevent deadlocks, making it ideal for libraries and server-side applications (e.g., ASP.NET Core).
Detailed Answer
Related To:
Direct Summary
In essence, ConfigureAwait(false) enables an asynchronous method’s continuation to resume on any available thread, optimizing performance by avoiding context capture. Conversely, ConfigureAwait(true) (the default behavior) captures the current SynchronizationContext and ensures the continuation resumes on the original thread, which is vital for UI responsiveness and consistency.
Introduction
Understanding the distinction between ConfigureAwait(false) and ConfigureAwait(true) is fundamental for effective asynchronous programming in C#. ConfigureAwait(false) avoids capturing the current SynchronizationContext, allowing the asynchronous method to resume on any available thread. ConfigureAwait(true), the default behavior, captures the context, typically forcing the continuation back onto the original thread, which is crucial for UI updates and specific threading models.
Key Concepts Explained
When to Use Which
Code Sample
This example demonstrates how ConfigureAwait(false) is typically used in a library method, while the UI method implicitly relies on ConfigureAwait(true) to ensure UI updates happen on the correct thread.
// Library method - designed for general use, no UI interaction needed
public async Task<string> GetDataAsync()
{
// Make an external API call
// ConfigureAwait(false) tells the runtime not to capture the current SynchronizationContext.
// This allows the continuation (the code after 'await') to run on any available thread,
// which is efficient for non-UI contexts.
var data = await httpClient.GetStringAsync("https://example.com/api/data").ConfigureAwait(false);
// Process data - this can happen on any thread, improving performance.
return ProcessData(data);
}
// UI method in a WPF application (or WinForms, UWP, etc.)
private async void Button_Click(object sender, RoutedEventArgs e)
{
// Update UI - This must happen on the UI thread.
this.statusText.Text = "Loading..."; // This line runs on the UI thread
// Call the library method.
// Although GetDataAsync() uses ConfigureAwait(false) internally,
// the 'await' here in the UI method implicitly uses ConfigureAwait(true) by default.
// This means after GetDataAsync() completes, the code following this 'await'
// will attempt to resume on the original UI thread.
var data = await GetDataAsync();
// Update UI with the received data - This must also run on the UI thread.
this.statusText.Text = data; // This line runs on the UI thread
}
private string ProcessData(string input)
{
// Some processing logic on the data (e.g., converting to uppercase)
return input.ToUpper();
}
Interview Hints
When discussing ConfigureAwait in an interview, consider highlighting these points with practical examples:

