zk-nvim is a free, open source publishing project written in Lua and released under GPL-3.0. It has 859 GitHub stars, 68 forks and 0 open issues, and was last pushed 6 days ago. On this registry it ranks #36 of 46 tracked projects in Publishing, with 5 head-to-head comparisons available. It gained 2 stars over the last 3 tracked days.

What is zk-nvim?

zk-nvim is a Neovim plugin that wires the Neovim editor to the zk plain text note-taking assistant, and it is for Neovim users who keep a Zettelkasten-style notebook of plain text or Markdown files and want to search, create and navigate those notes without leaving the editor.

What it is

zk-nvim is a Lua plugin for Neovim that acts as a client in front of the zk command line note-taking assistant. It lives in the Neovim plugin ecosystem and depends on the zk CLI as its backend, so the plugin does not implement note indexing, linking or querying itself; it drives the zk binary, including the language server started with zk lsp, and presents the results through Neovim's built-in interfaces and popular picker plugins.

The concrete problem it solves is the friction of using a plain text note system from inside an editor. Without it, a note-taker has to drop to a shell to run zk commands, search notes outside the editor, and manually wire completion and navigation for note links. zk-nvim replaces that manual, out-of-editor workflow with in-editor commands such as :ZkNotes and :ZkNew, an automatically attached LSP client, and picker-driven search over the notebook.

Key capabilities

  • Starts an LSP client for the notebook with cmd = { "zk", "lsp" } and filetypes = { "markdown" }, providing completion, hover and go-to-definition inside note buffers.
  • Automatically attaches the LSP client to buffers inside a zk notebook when auto_attach = { enabled = true } is set.
  • Provides built-in commands for notebook work, including :ZkNotes and :ZkNew.
  • Supports several picker backends selected through the picker option: telescope, fzf, fzf_lua, minipick, snacks_picker, and select via vim.ui.select.
  • Accepts picker_options for per-picker configuration, such as a Telescope ivy theme or a snacks picker layout.preset.
  • Controls how multiple tags combine in a ZkTags search through tags.multi_select_strategy, set to "AND" or "OR".
  • Discovers the notebook automatically, checking the current buffer path, then the current working directory, then the $ZK_NOTEBOOK_DIR environment variable; an explicitly supplied path to any file or directory inside a notebook overrides that order.

Who uses it and how

  • Individual writers and developers who keep a personal wiki or Zettelkasten notebook as plain text and want note creation, search and link navigation from within Neovim.
  • Users who already run a picker such as Telescope, fzf, mini.pick or snacks.picker and want notebook search routed through it rather than through a separate interface.
  • Neovim users on plugin managers including lazy.nvim, packer.nvim and vim-plug, who configure the plugin with a single spec and pass options through opts.
  • People maintaining more than one notebook, who rely on explicit paths for per-invocation targeting or export $ZK_NOTEBOOK_DIR so that a notebook can always be found.
  • Contributors and users coordinating through Matrix at #zk-org:pub.solar, described in the README as the channel for general, support and development discussion.

Getting started

Install the plugin through packer.nvim with use("zk-org/zk-nvim"), through vim-plug with Plug 'zk-org/zk-nvim', or through lazy.nvim with the "zk-org/zk-nvim" spec, and ensure the zk CLI and Neovim are present. Version 0.4.0 through HEAD requires zk 0.15.1 or later and Neovim 0.11.0 or later, and the README notes that when the zk CLI is installed there is no need to install zk lsp separately via Mason or otherwise.

How it compares

The facts do not list any paid or proprietary products that this project replaces, so no licence, hosting or cost comparison can be drawn. Among the tools named, zk-nvim is distinct in kind: Telescope, fzf, mini.pick and snacks.picker are picker front ends that zk-nvim integrates with rather than competes against, and the zk CLI is its required backend. It stands alone in this registry as the Neovim client for zk.

When to use it — and when not to

A user must already have the zk CLI installed and Neovim 0.11.0 or later, and picker integrations only work if the corresponding picker plugin is installed, so anyone unwilling to run the zk toolchain should not adopt it. The plugin adds no key mappings by default, which means the user writes their own mappings from the example, and it deliberately delegates indexing, querying and link resolution to the external binary rather than implementing them. Readers should also note that the supplied README excerpt is partial, ending part way through the built-in commands section, so the command surface is not fully documented in the available facts.

project readme (upstream, from github) — read inline

zk-nvim

Neovim extension for the zk plain text note-taking assistant.

Checkout Shivan's video, Note-taking System ALL Programmers Should Consider, to see it in action.

Join us on Matrix for general, support and development discussion: #zk-org:pub.solar.

Requirements

zk-nvim zk Neovim
0.4.0 - HEAD >=0.15.1 >= 0.11.0
0.2.0 - 0.3.0 0.14.1 - 0.15.1 0.9.5 - 0.10.4
0.1.1 0.13.0 - 0.14.1 0.9.5
0.1.0 0.13.0 - 0.14.1 0.8.0 - 0.9.5

Installation

Via packer.nvim

use("zk-org/zk-nvim")

Via vim-plug

Plug 'zk-org/zk-nvim'

Via lazy.nvim

{
  "zk-org/zk-nvim",
  name = "zk",
  opts = {
    -- See Setup section below
  },
}

To get the best experience, it's recommended to also install either Telescope, fzf, mini.pick, or snacks.picker

Setup

[!IMPORTANT]
If you have the zk cli installed, then you do not need to install zk lsp via Mason (or otherwise).

Default lazy.nvim setup:

return {
  "zk-org/zk-nvim",
  name = "zk",
  opts = {
    -- Can be "telescope", "fzf", "fzf_lua", "minipick", "snacks_picker",
    -- or select" (`vim.ui.select`).
    picker = "select",

    lsp = {
      -- `config` is passed to `vim.lsp.start(config)`
      config = {
        name = "zk",
        cmd = { "zk", "lsp" },
        filetypes = { "markdown" },
        -- on_attach = ...
        -- etc, see `:h vim.lsp.start()`
      },

      -- automatically attach buffers in a zk notebook that match the given filetypes
      auto_attach = {
        enabled = true,
      },
    },

    tags = {
      -- Configure how multiple tags should be combined in a ZkTags search
      -- Can be "AND" or "OR"
      multi_select_strategy = "AND",
    }
  },
}

Note that this will not add any key mappings for you. If you want to add key mappings, see the example mappings.

Picker Options

You can define default configurations for the pickers opened by zk-nvim, allowing you to apply a specific theme or layout for zk-nvim. This works for all supported pickers, but you'll need to refer to the relevant configuration options for each picker.

require("zk").setup({
    picker_options = {
        telescope = require("telescope.themes").get_ivy(),

        -- or if you use snacks picker

        snacks_picker = {
            layout = {
                preset = "ivy",
            }
        },
    },
    ...
})

Notebook Directory Discovery

When you run a notebook command, this plugin will look for a notebook in the following places and order:

  1. the current buffer path (i.e. the file you are currently editing),
  2. the current working directory,
  3. the $ZK_NOTEBOOK_DIR environment variable.

We recommend you to export the $ZK_NOTEBOOK_DIR environment variable, so that a notebook can always be found.

It is worth noting that for some notebook commands you can explicitly specify a notebook by providing a path to any file or directory within the notebook. An explicitly provided path will always take precedence and override the automatic notebook discovery. However, this is always optional, and usually not necessary.

Getting Started

After you have installed the plugin and added the setup code to your config, you are good to go. If you are not familiar with zk, we recommend you to read through the getting started guide.

When using the default config, the zk LSP client will automatically attach itself to buffers inside your notebook and provide capabilities like completion, hover and go-to-definition; see https://github.com/zk-org/zk/issues/22 for a full list of what is supported.

Try out different commands such as :ZkNotes or :ZkNew, see what they can do, and learn as you go.

Built-in Commands

Indexing

Options (ZkIndex)

  • :ZkIndex [{options}]
    Indexes the notebook.

Creating Notes

Options (ZkNew)

  • :ZkNew [{options}]
    Creates and edits a new note.

  • :'ZkNewFromTitleSelection [{options}]
    Creates a new note from the visual selection (used as the title) and replaces the selection with a link to the note (unless append = true is passed to options).

  • :'ZkNewFromContentSelection [{options}]
    Creates a new note from the visual selection (used as the content) and replaces the selection with a link to the note (unless append = true is passed to options).

Navigation

Options (ZkList)

  • :ZkCd [{options}]
    Changes directory to the notebook root.

  • :ZkNotes [{options}]
    Opens a notes picker.

  • :ZkBuffers [{options}]
    Opens a notes picker for active buffers (notebook files only).

  • :ZkBacklinks [{options}]
    Opens a notes picker showing backlinks of the current buffer.

  • :ZkLinks [{options}]
    Opens a notes picker showing outbound links of the current buffer.

Linking

Options (ZkList)

  • :ZkInsertLink
    Inserts a link at the cursor location.

  • :'ZkInsertLinkAtSelection [{options}]
    Inserts a link around the selected text.

    • Special option: matchSelected = true → filters notes similar to the selection.

Searching & Tagging

Options (ZkList)

  • :ZkMatch [{options}]
    Opens a notes picker, filtering for notes matching a search term. The term is resolved from, in priority order: an explicit options.match (see the match option in Options (ZkList)), a visual selection (:'ZkMatch), or — in normal mode — the word under the cursor.

  • :ZkTags [{options}]
    Opens a notes picker for selected tags.

In addition, options.notebook_path can be used to explicitly specify a notebook by providing a path to any file or directory within the notebook; see Notebook Directory Discovery.

Examples:

:ZkNew { dir = "daily", date = "yesterday" }
:ZkNotes { createdAfter = "3 days ago", tags = { "work" } }
:'<,'>ZkNewFromTitleSelection " this will use your last visual mode selection. Note that you *must* call this command with the '<,'> range.
:ZkCd
:ZkMatch { match = { "foo", "bar" } } " search notes matching "foo" or "bar"
:ZkMatch { sort = { "created" } } " no match given, falls back to the word under the cursor (or visual selection)

Via Lua

You can access the underlying Lua function of a command, with require("zk.commands").get.

Examples:

require("zk.commands").get("ZkNew")({ dir = "daily" })
require("zk.commands").get("ZkNotes")({ createdAfter = "3 days ago", tags = { "work" } })
require("zk.commands").get("ZkNewFromTitleSelection")()

Custom Commands

---A thin wrapper around `vim.api.nvim_add_user_command` which parses the `params.args` of the command as a Lua table and passes it on to `fn`.
---@param name string
---@param fn function
---@param opts? table {needs_selection} makes sure the command is called with a range
---@see vim.api.nvim_add_user_command
require("zk.commands").add(name, fn, opts)

Example 1:

Let us add a custom :ZkOrphans command that will list all notes that are orphans, i.e. not referenced by any other note.

local zk = require("zk")
local commands = require("zk.commands")

commands.add("ZkOrphans", function(options)
  options = vim.tbl_extend("force", { orphan = true }, options or {})
  zk.edit(options, { title = "Zk Orphans" })
end)

This adds the :ZkOrphans [{options}] vim user command, which accepts an options Lua table as an argument. We can execute it like this :ZkOrphans { tags = { "work" } } for example.

Note: The zk.edit function is from the high-level API, which also contains other functions that might be useful for your custom commands.

Example 2:

Chances are that this will not be our only custom command following this pattern. So let's also add a :ZkRecents command and make the pattern a bit more reusable.

readme truncated — read the full docs on github

Frequently asked questions

Is zk-nvim free to use?

zk-nvim is open source under the GPL-3.0 licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does zk-nvim do?

Neovim plugin for zk

What is zk-nvim written in?

zk-nvim is primarily written in Lua. Its source is publicly available at https://github.com/zk-org/zk-nvim, and it has 859 GitHub stars.