DEV Community

Cover image for Are async blocks dead? Introducing async closures (rust 1.85)
Toluwanimi for Mastering Backend

Posted on • Originally published at masteringbackend.com on

Are async blocks dead? Introducing async closures (rust 1.85)

Are async blocks dead? Introducing async closures (rust 1.85)

We just saw the official release of Rust’s 1.85 version, and a lot of wow changes came with it, one of them would be async closures.

This new feature has caused a lively debate in the Rust community: Are async blocks, a staple of Rust’s async ecosystem, now obsolete? Are they useless?

As of February 28, 2025, the answer seems clear-async blocks are far from dead. Instead, they coexist with async closures, each serving unique purposes in Rust’s ever-evolving toolkit for non-blocking code.

Looking into what this means for developers and why both features remain relevant.

The Basics: Async Blocks vs. Async Closures

To understand what is going on, we first need to understand the two key terms. Async blocks, written as async { ... }, have been around since Rust's async/await syntax debuted in version 1.39.

They create a single, anonymous future-essentially a one-and-done piece of asynchronous work, just like a normal code block {//code logic} but with async privileges.

Here’s a simple example:

let future = async {
    println!("Running an async block!");
};
future.await;
Enter fullscreen mode Exit fullscreen mode

They’re straightforward, perfect for encapsulating a specific task without reusable structure.

Now, async closures are stabilized in Rust 1.85, with the syntax async |param| { ... }. These are callable async functions that return a new future each time they're invoked.

For example:

let closure = async |message: &str| {
    println!("Message: {}", message);
};
closure("Hello, Rust!").await;
Enter fullscreen mode Exit fullscreen mode

Unlike async blocks, async closures can take parameters and be reused.

This makes them ideal for scenarios where you want flexibility and callability.

So what’s the big new with them?

Async closures address two long-standing limitations in Rust’s async model.

  • First, they enable higher-ranked async function signatures, like think passing async functions as arguments to other functions.
  • Second, they allow futures to borrow from captured variables more naturally, like you with a normal closure, enhancing ergonomics. For example, a situation where you need to process multiple tasks dynamically:
let tasks = vec![
    async |url: &str| { println!("Fetching {}", url); },
    async |path: &str| { println!("Reading {}", path); },
];
for task in tasks {
    task("example.com").await;
}
Enter fullscreen mode Exit fullscreen mode

This kind of reusable, parameterized async logic was difficult before Rust 1.85, but thanks to async closures, it is now fixed.

Are Async Blocks Obsolete?

So, with async closures in the picture, do we still need async blocks? Absolutely. The two features aren’t rivals-they’re teammates. Async blocks shine in simplicity. When you need a one-off future, like fetching data in a single function, they’re the go-to:

async fn fetch_data() -> String {
    let response = async {
        // Simulate an HTTP request
        "Data received".to_string()
    }.await;
    response
}
Enter fullscreen mode Exit fullscreen mode

No parameters, no reuse, OTOH, and async closures, by contrast, are overkill for such cases but excel in complex scenarios, like event handlers or callbacks requiring repeated execution. So you see, they are just different things, not really enemies.

What does the community think, and what does this mean for you as a developer

The Rust community agrees. Discussions on forums and insights from sources like the Rust Changelogs for 1.85.0 suggest that async blocks remain fundamental. They’re not going anywhere; they’re just sharing the stage with a more versatile variant.

Practical Implications for Developers

For Rust developers, this means more options, not a replacement. Use async blocks for quick, inline async tasks-think of them as the lightweight, single-use tool in your kit.

Reach for async closures when you need reusable async logic, especially in higher-order functions or when passing async behavior around. Here’s a quick guide:

  • Async Blocks: One-time futures, simple operations (e.g., inline data fetching).
  • Async Closures: Reusable async functions and parameterized tasks (e.g., dynamic task processing).

Now that you have an idea of the all-new async closures in rust, you might want to update your code base to reflect this beautiful change, increase your readability, and remove those weird async closure walkarounds like wrapping an async block in a rust closure. If you have any issues understanding this, feel free to reach out to me on my LinkedIn if you need more clarification.

P.S. This was what I meant by an async closure walkaround; it was used before the stabilization of async closures.

In the code, you create a normal closure, but the closure’s block is async’ed, and a move is added so you do not have borrow issues; instead, all the values used are used once.

let async_closure_walkaround = || async move {};
Enter fullscreen mode Exit fullscreen mode

Play around with this feature so you get a feel for it. See the Rust playground for more practice.


Thank you for being a part of the community

Before you go:

Whenever you’re ready

There are 4 ways we can help you become a great backend engineer:

  • The MB Platform: Join thousands of backend engineers learning backend engineering. Build real-world backend projects, learn from expert-vetted courses and roadmaps, track your learnings and set schedules, and solve backend engineering tasks, exercises, and challenges.
  • The MB Academy: The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.
  • Join Backend Weekly: If you like posts like this, you will absolutely enjoy our exclusive weekly newsletter, sharing exclusive backend engineering resources to help you become a great Backend Engineer.
  • Get Backend Jobs: Find over 2,000+ Tailored International Remote Backend Jobs or Reach 50,000+ backend engineers on the #1 Backend Engineering Job Board.

Originally published at https://masteringbackend.com on March 12, 2025.


Top comments (0)