Skip to main content

Plugin Overview

BETA

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

TypePurposeInvoked By
FunctionalRuns arbitrary Lua code and may emit eventsKeybinding with run = "plugin foo"
PreviewerGenerates preview content for a file typeFile hover / [open] rules
PreloaderPre-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 access cx.
-- 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:

FunctionContextPurpose
entry(job)AsyncMain entry for functional plugins
entry_sync(job)SyncMain entry for functional plugins (sync)
setup()SyncCalled 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
info

When both entry and entry_sync are defined, Yazi calls entry_sync by default. The --sync flag in the keybinding forces sync mode.