Neovim Merges vim.async, Bringing Trio-Style Structured Concurrency to Lua Plugin Development
Neovim's Lua standard library gains vim.async, a structured-concurrency module merged into master and milestoned for the 0.13 release.
Overview
Neovim’s Lua standard library has gained a new vim.async namespace, a structured-concurrency module for writing non-blocking plugin code, according to InfoQ. The feature merged into Neovim’s master branch on September 3, 2026, as pull request #34473, and is milestoned for Neovim’s 0.13 release, according to the pull request itself.
What We Know
- Before
vim.async, Neovim plugin authors handling asynchronous work such as filesystem operations, background processes, and network calls “relied on event-loop bindings provided by Libuv via vim.uv (formerly vim.loop), or external libraries such as plenary.nvim and async.nvim,” which “often led to deeply nested callbacks or divergent coroutine implementations,” according to InfoQ. - The pull request’s own description frames the same problem: “Nvim has many Lua APIs that start callback-driven work: timers, jobs, libuv handles, and other event-loop tasks,” according to the pull request.
- The new module’s design “is similar to Trio: work has an owner, tasks are awaited explicitly, and cancellation is cooperative,” according to the pull request — a reference to the structured-concurrency model used by Python’s Trio library.
- According to Neovim’s official documentation, vim.async is a “structured async API for Lua code that waits on event-loop work.” Tasks are created with
vim.async.run(), and “a task created while another task is running becomes a child of that task, and its function starts when the parent reaches its next checkpoint.” - Error handling follows the same hierarchy: “if a child fails without being handled, the parent fails and closes the remaining children,” according to the documentation. Cancellation works the same way — “Task:close() marks a task as closing, and the task observes that state at a checkpoint,” per the documentation.
- The module also adds
vim.async.semaphore()to cap concurrent tasks,vim.async.timeout()to apply cancellation deadlines,vim.async.iter()to consume multiple tasks’ results in completion order, andvim.async.pawait(), a protected-await variant for handling expected failures, according to the documentation.Task:detach()lets a background task be promoted to an independent, top-level task rather than staying tied to its parent’s lifecycle, per the same documentation. - The pull request was authored by GitHub user lewis6991 and lists justinmk among the reviewers who approved the change, according to the pull request. It closes issue #19624, filed under the description “Lua: structured concurrency, Promises, task pipelines,” according to the pull request.
- According to InfoQ, reaction among Neovim users was largely positive: the outlet reported that participants in an r/neovim discussion thread titled “vim.async has been merged” welcomed the addition of structured concurrency to core, and that commenters discussed how a unified abstraction could reduce plugin dependency collisions caused by competing third-party coroutine libraries.
What We Don’t Know
- Because vim.async is milestoned for Neovim 0.13 rather than already part of a shipped stable release, it isn’t yet clear when 0.13 itself will be released or what else will ship alongside it.
- Available sources don’t specify how many existing plugins will migrate from plenary.nvim or async.nvim to vim.async, or on what timeline.