Plugin Overview
The plugin system is in beta. The API is considered stable but may receive breaking changes. Pin your Yazi version when relying on plugins.
Directory Structure
Each plugin lives in its own directory under ~/.config/yazi/plugins/ with a .yazi suffix:
~/.config/yazi/plugins/
├── foo.yazi/
│ ├── main.lua # Entry point
│ ├── README.md # Documentation
│ └── LICENSE # License file
├── bar.yazi/
│ ├── main.lua
│ └── README.md
└── chacha.yazi/
└── main.lua
main.lua
The entry point file. Yazi loads and executes main.lua when the plugin is invoked. It must return a table with the plugin's entry functions.
Plugin Types
| Type | Purpose | Invoked By |
|---|---|---|
| Functional | Runs arbitrary Lua code and may emit events | Keybinding with run = "plugin foo" |
| Previewer | Generates preview content for a file type | File hover / [open] rules |
| Preloader | Pre-processes files for preview (e.g., archive extraction) | File hover before preview |
Sync vs Async Contexts
Plugins execute in one of two contexts:
- Sync — Runs on the main thread. Can read UI state (
cx) and modify it. Cannot perform I/O. Use for fast operations. - Async — Runs on a worker thread. Can perform I/O, spawn subprocesses, and use
ya.emit()to send events back to the main thread. Cannot directly accesscx.
-- Sync entry point
function entry_sync(job)
local cx = job.cx
-- Read UI state, emit events
end
-- Async entry point
function entry(job)
-- I/O, blocking operations
ya.emit("my_event", { ... })
end
Ownership Transfer Rules
Yazi enforces ownership rules when passing values between sync and async contexts:
- A value can be used in only one context at a time
- If both sync and async code need access to the same value, clone it explicitly
- Ownership is transferred when passing a value to an async callback
-- Ownership transfer example
local file = cx.active.current.hovered
-- file is now owned by this sync context
ya.sync(function()
-- file cannot be used here without cloning
end)
Sendable Values
Values that can be safely sent between contexts are marked as Sendable. See Plugin Aliases for the complete list of Sendable types.
Entry Points
Plugins define one or more of these functions in their returned table:
| Function | Context | Purpose |
|---|---|---|
entry(job) | Async | Main entry for functional plugins |
entry_sync(job) | Sync | Main entry for functional plugins (sync) |
setup() | Sync | Called once when the plugin is first loaded (optional) |
local my_plugin = {}
function my_plugin.entry(job)
-- async logic
end
function my_plugin.setup()
-- initialization
end
return my_plugin
When both entry and entry_sync are defined, Yazi calls entry_sync by default. The --sync flag in the keybinding forces sync mode.