Developer Tools
Neovim introduces structured async/await library to tame plugin concurrency
A new vim.async module brings standardized task management and error handling to Neovim, replacing fragmented coroutine patterns across the plugin ecosystem.
InfoQ
Neovim has integrated a native structured concurrency library into its Lua standard library, providing plugin developers with a unified way to handle asynchronous work—network calls, file I/O, and background processes—without stalling the editor's event loop.
Moving past callback hell#
For years, Neovim plugins juggled asynchronous operations through low-level Libuv bindings (via vim.uv) or competing third-party libraries like plenary.nvim and async.nvim. This fragmentation produced deeply nested callbacks, inconsistent error handling, and plugin conflicts when different libraries used incompatible coroutine wrappers. The new vim.async namespace aims to end that era by baking concurrency primitives directly into the core.
How structured tasks work#
The model centers on tasks spawned via vim.async.run(). When code hits vim.async.await(), the task yields control back to the event loop, letting Neovim process user input and synchronous operations without pause. Parent tasks automatically manage child task lifecycles—a parent won't finish until all its children do, and uncaught exceptions in a child bubble up to the parent and cancel siblings unless explicitly isolated. For background work that should outlive its initiator, Task:detach() promotes it to a top-level task.
Synchronization and error safety#
The toolkit includes semaphores to throttle concurrent operations, timeouts for cancellation deadlines, and vim.async.iter() to consume results in completion order rather than launch order. For expected failures, vim.async.pawait() mirrors Lua's pcall(), returning a status flag alongside results or errors—keeping the calling code flexible when operations may fail without derailing the whole task.
Community embrace#
Developers on r/neovim celebrated the merge, noting that bare Libuv callbacks have long been error-prone and that a unified abstraction resolves ecosystem pain points like library collisions. The discussion also dug into error propagation semantics and how interacts with traditional callback conventions.

