<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j" -->

---
title: Zig's new plan for asynchronous programs | daily.dev
description: Zig's designers have announced a new approach to asynchronous I/O that avoids the function coloring problem. The design centers on a new generic interface...
canonical: https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Zig's new plan for asynchronous programs | daily.dev
og:description: Zig's designers have announced a new approach to asynchronous I/O that avoids the function coloring problem. The design centers on a new generic interface...
og:url: https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j
og:image: https://api.daily.dev/og/posts/ac61cO56j.png
og:image:alt: Zig's new plan for asynchronous programs
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Zig's new plan for asynchronous programs

**[Lobsters](https://daily.dev/sources/lobsters)** · 10 min read · 5 upvotes · 3 comments

## Summary

Zig's designers have announced a new approach to asynchronous I/O that avoids the function coloring problem. The design centers on a new generic interface called `Io`, passed as a parameter to functions that need I/O — similar to how Zig's `Allocator` interface works. Two built-in implementations are provided: `Io.Threaded` (uses synchronous syscalls, optionally dispatching to threads) and `Io.Evented` (uses io_uring, kqueue, or other async backends). Code written against the `Io` interface works correctly with either backend, making asynchronicity a transparent performance optimization rather than a code-structure concern. Two functions, `async()` and `concurrent()`, distinguish between operations that can be parallelized opportunistically versus those that must run simultaneously for correctness. The design avoids new language keywords, letting programmers use existing control-flow primitives like `try` and `defer`. `Io.Evented` is still experimental and incomplete, and a WebAssembly-compatible `Io` variant is planned. This is one of the last major design questions before Zig's 1.0 release.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://lwn.net/SubscriberLink/1046084/6cb9e4e1fd82a90d>

## Questions this post answers

### How does Zig's new Io interface solve the function coloring problem for async code?

Zig functions that perform I/O take an Io interface instance as a parameter, similar to the Allocator pattern for memory. The same function works with either Io.Threaded (synchronous, using threads only when explicitly parallelized) or Io.Evented (event-loop based, using io_uring or kqueue), so library authors write one version of a function that runs correctly under either execution model without special async syntax.

_Developers weighing Zig's approach against Rust or Python's async syntax can track ecosystem shifts like this on daily.dev._

### What is the difference between async() and concurrent() in Zig's new Io interface?

async() only guarantees the operation completes by the time its result is awaited; under Io.Threaded it may run immediately with no real parallelism, treating concurrency purely as an optimization. concurrent() explicitly forces simultaneous execution, using a thread pool under Io.Threaded, and is required when two operations must run in parallel for correctness, such as listening on a socket while handling user input.

_Anyone adapting existing Zig I/O code can follow daily.dev to stay current on async and concurrency changes._

### Is Zig's Io.Evented asynchronous I/O implementation ready for production use?

No, Io.Evented is still experimental and lacks implementations for all supported operating systems. A third Io variant compatible with WebAssembly is planned but depends on other unimplemented language features, and the original pull request for the Io interface lists 24 planned follow-up items still needing work.

_Teams evaluating Zig's readiness for async workloads can follow daily.dev for updates before committing to it in production._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 30 comments across hackernews, lobsters (as of 2026-09-14).

**TL;DR:** Commenters are broadly interested in Zig's new Io design and find the async/concurrent distinction conceptually sound, but a lively debate has emerged over whether the terminology—especially reusing the word

**Sentiment:** 55% positive · 35% mixed · 10% skeptical

**The pushback**

- The naming of `io.async` is seen as confusing because the broader industry treats "async" as implying non-synchronous (concurrent) execution, making the Zig-specific definition a potential teaching footgun.
- Some commenters question whether more complex server-side patterns (beyond simple fan-out/join) are well-served by the current design.
- The distinction between `io.async` and `io.concurrent` adds conceptual overhead that may not be immediately intuitive to developers coming from other ecosystems.

**By community**

- hackernews (mixed): No substantive comments were present, so no signal is available beyond the low point count.
- lobsters (mixed): Engaged discussion finds the async/concurrent distinction technically justified but debates whether the terminology is intuitive, with core Zig contributors actively defending the design choices.

**Hottest debate:** Whether naming the "possibly-concurrent" primitive `io.async` is intuitive or a footgun, given that the industry broadly conflates "async" with "concurrent" execution.

**Open questions**

- How does std.Io handle more complex server patterns beyond simple parallel fan-out and join?
- Could a future `io.Debug` or similar mode enforce stricter concurrency checking during development?
- Will a stackless-coroutine Io implementation be provided alongside Io.Evented and Io.Threaded?
- Can a Future created by `io.async` later be promoted to run concurrently without re-submitting the task?

**Highlights**

> > This feels like a major footgun for teaching Zig, requiring you to detach these words solely for this language. Which could be fine, but I must ask, what is the value in doing so? The precision feels unnecessary. Let's imagine that I write a library, let's call it `robust-file-saver`, which saves a user-provided string to two files (hence the *robust* part of the name). You could write it like this:  ``` fn robustFileSaver(data: []const u8) !void {    try writeToFile("fileA.txt", data);    try writeToFile("fileB.txt", data); } ``` This works, but when run in a context where concurrency is available (e.g. multithreaded process), you won't be able to fully exploit it because you didn't express in your code that the second call to `writeToFile` doesn't have to wait for the first to be done before starting. Here's how you can express the extra flexibility in Zig: ``` fn robustFileSaver(data: []const u8) !void {    var a_future = io.async(writeToFile, .{"fileA.txt", data});    var b_future = io.async(writeToFile, .{"fileB.txt", data});    try a_future.await();    try b_future.await(); } ```   This code expresses that the two tasks (writing to a file) are *asynchronous* (they don't care about each other, roughly speaking) and so in a concurrent context they can be run "at the same time" (i.e. concurrently). When this program runs over `Io.Threaded` the two calls will run on two different threads in the general case. That said, even more importantly, `io.async` doesn't mean that the program **must** have concurrency support so if we use `Io.Threaded` but make a single-threaded build of the program (`zig build-exe -fsingle-threaded`), then the two calls will happen sequentially one after the other, because that's fine too. When running two tasks sequentially would instead produce wrong behavior, you have to use `io.concurrent`. The article has a good example: if you want to make a program that both reads from a socket and also reacts to user input (e.g. a chat application), then you have to use `io.concurrent`. ``` io.async(readNetwork, .{}); io.async(handleUserInput, .{}) ``` This code is wrong because you are saying that it's also fine to first read from the network and, only once the connection cloces, to start handling user input. ``` try io.concurrent(readNetwork, .{}); try io.concurrent(handleUserInput, .{}) ``` This code is correct because you need both things to happen concurrently. And this is also what allows us to prevent surprise deadlocks when you make single-threaded builds of applications that use Io.Threaded: if you can't spawn threads (which are the unit of concurrency of Io.Threaded), then it's impossible to progress both `readNetwork` and `handleUserInput` at the same time, and so you get an error right away.  Without the distinction between `io.async` and `io.concurrent` we wouldn't know which code is safe to run sequentially and which will misbehave instead. Other languages don't make that distinction because any usage of async/await immediately opts you into a concurrent execution context, which is also why languages end up with an ecosystem split of async vs non-async versions of essentially the same libraries. In Zig you can decide to create a program that uses `Io.Threaded`, which uses exclusively blocking I/O syscalls, build in single-threaded mode, and you will still be able to use a library that internally uses `io.async`, like `robust-file-saver` from before.  At the same time users that do want to opt into `Io.Evented` or multithreaded `Io.Threaded` will also be able to use `robust-file-saver` and they won't get a performance penalty because `io.async` calls will correctly leverage the concurrent execution context.
> — [kristoff on lobsters · 6 points, 1 comments](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs#c_h1l32s)

> > Without the distinction between io.async and io.concurrent we wouldn't know which code is safe to run sequentially and which will misbehave instead. I understand why the distinction exists, my issue is with the taxonomy used for the distinction, and that it reuses established words with unintuitive definitions. If I say something is _asymmetrical_, I don't mean that it can _possibly be symmetrical_. When most people are talking about Asynchronous Execution, they are speaking of execution that is _not synchronous_, not that it is _possibly synchronous_. Your original article quoted the wikipedia pages for concurrency and parallel, but you skipped [asynchrony](https://en.wikipedia.org/wiki/Asynchrony_(computer_programming)). The first example it gives is: > Asynchronous procedure call, a method to run a procedure concurrently, a lightweight alternative to threads. Wikipedia doesn't have to be authoritative and Zig can do whatever it wishes, but I'm struggling to find any usage of async that doesn't immediately imply or explicitly state we're that we're talking about non-synchronous execution. This definition of asynchronous being 'possibly out of order' seems novel? This is why my `io.maybeAsync` feels more natural. It communicates the intent better for those that have assumed asynchronous implies concurrency (which I would argue is the whole industry). > Other languages don't make that distinction because any usage of async/await immediately opts you into a concurrent execution context, which is also why languages end up with an ecosystem split of async vs non-async versions of essentially the same libraries. This feels overstated. Weirdly enough this feels like 3 colors: always blocking (no `io`), possibly blocking (using `io.async` only), not blocking (using `io.concurrent`). I still have to opt into `io` semantics when building out my library, but now I get the extra tool to make functions that don't require concurrency. The only difference is you guys had the foresight to make [every fs function async](https://codeberg.org/ziglang/zig/src/commit/d73fbcc3ae920eef4bc0b41df2a4cf74966dd01f/lib/std/Io/File.zig#L218) before tagging 1.0, while Rust of course [didn't](https://github.com/smol-rs/async-fs).
> — [jado on lobsters · 6 points, 3 comments](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs#c_maqqvz)

> It looks good for “do N things possibly in parallel then join” but that’s the simplest case. I want to see if and how std.Io would express more complicated patterns like you need in servers. I filed an issue about it here: https://github.com/ziglang/zig/issues/26056
> — [mk12 on lobsters · 10 points, 2 comments](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs#c_7phjjt)

> Indeed, `std.Io.Threaded` dispatches async operations into a configurably sized thread pool. However, `async` is infallible, which means the callsite must be able to tolerate the function being called directly in case a thread or closure cannot be allocated.
> — [andrewrk on lobsters · 8 points, 1 comments](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs#c_9trilr)

> [Loris Cro (VP of Zig Community) discussing the article](https://www.youtube.com/watch?v=JY2Zxu7kngc)
> — [Miaourt on lobsters · 12 points](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs#c_pebllh)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=46131986) · 8 points · 0 comments
- [lobsters](https://lobste.rs/s/uzfrya/zig_s_new_plan_for_asynchronous_programs) · 56 points · 30 comments

## Community discussion

Top comments from developers on daily.dev.

**@bangursis** · 1 upvotes

> The link seems to be broken :(

## Similar posts on daily.dev

- [Zig's New Async I/O \(Text Version\)](https://daily.dev/posts/zig-s-new-async-i-o-text-version--ikopqzdkc) · Lobsters · 7 upvotes · 0 comments
- [Async I/O in Zig 0.16, today](https://daily.dev/posts/async-i-o-in-zig-0-16-today-tn11ikcsj) · Lobsters · 13 upvotes · 1 comments
- [Zig’s Io.Threaded is Neat](https://daily.dev/posts/zig-s-io-threaded-is-neat-asnt4devz) · matklad · 16 upvotes · 1 comments

---

Tags: [#zig](https://daily.dev/tags/zig)

[View this post on daily.dev](https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Zig's new plan for asynchronous programs","url":"https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j"},"datePublished":"2026-08-11T01:57:55.469Z","dateModified":"2026-09-14T06:16:56.077Z","description":"Zig's designers have announced a new approach to asynchronous I/O that avoids the function coloring problem. The design centers on a new generic interface...","image":"https://media.daily.dev/image/upload/s--0_ODbtD2--/f_auto/v1722860399/public/Placeholder%2008","thumbnailUrl":"https://media.daily.dev/image/upload/s--0_ODbtD2--/f_auto/v1722860399/public/Placeholder%2008","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":3,"discussionUrl":"https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":5},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":3}],"keywords":"zig","timeRequired":"PT10M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"Zig's new plan for asynchronous programs"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j","comment":[{"@type":"Comment","text":"The link seems to be broken :(","datePublished":"2026-08-11T09:31:56.814Z","url":"https://daily.dev/posts/ac61cO56j#c-EGH0o21FP","author":{"@type":"Person","name":"Arthur","url":"https://daily.dev/bangursis","image":"https://media.daily.dev/image/upload/s--zxHa8Jbn--/f_auto/v1756385859/avatars/avatar_8cefb1381e76492fb74972498d0615c5?_a=BAMClqZW0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/zig-s-new-plan-for-asynchronous-programs-ac61co56j#faq","mainEntity":[{"@type":"Question","name":"How does Zig's new Io interface solve the function coloring problem for async code?","acceptedAnswer":{"@type":"Answer","text":"Zig functions that perform I/O take an Io interface instance as a parameter, similar to the Allocator pattern for memory. The same function works with either Io.Threaded (synchronous, using threads only when explicitly parallelized) or Io.Evented (event-loop based, using io_uring or kqueue), so library authors write one version of a function that runs correctly under either execution model without special async syntax. Developers weighing Zig's approach against Rust or Python's async syntax can track ecosystem shifts like this on daily.dev."}},{"@type":"Question","name":"What is the difference between async() and concurrent() in Zig's new Io interface?","acceptedAnswer":{"@type":"Answer","text":"async() only guarantees the operation completes by the time its result is awaited; under Io.Threaded it may run immediately with no real parallelism, treating concurrency purely as an optimization. concurrent() explicitly forces simultaneous execution, using a thread pool under Io.Threaded, and is required when two operations must run in parallel for correctness, such as listening on a socket while handling user input. Anyone adapting existing Zig I/O code can follow daily.dev to stay current on async and concurrency changes."}},{"@type":"Question","name":"Is Zig's Io.Evented asynchronous I/O implementation ready for production use?","acceptedAnswer":{"@type":"Answer","text":"No, Io.Evented is still experimental and lacks implementations for all supported operating systems. A third Io variant compatible with WebAssembly is planned but depends on other unimplemented language features, and the original pull request for the Io interface lists 24 planned follow-up items still needing work. Teams evaluating Zig's readiness for async workloads can follow daily.dev for updates before committing to it in production."}}]}
```

