Library / SDK
neovim/pynvim avatar
neovim/pynvim

Pynvim Python Client and Plugin Host for Neovim

Python client and plugin host for Nvim

1,707 stars132 forksPythonApache-2.0

At a glance

What is it?
Pynvim connects Python applications and plugins to Neovim through msgpack-rpc, Vim script interfaces, and Neovim's remote plugin system. It suits Python 3.10 or later users, with one important boundary around Vimscript dictionary references.
Who is it for?
Adopt Pynvim when Python code must control Neovim or implement a remote plugin, especially when asynchronous operation and object access to buffers, windows, API functions, and Vimscript functions matter. Do not choose it for Python 3.9 or earlier, for code that requires live Vimscript dictionary references, or for a plugin that must remain entirely inside Neovim without Python.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Pynvim's Python-to-Neovim bridge

Pynvim addresses two related problems. It provides the Python runtime needed by Neovim's `:python3` plugin interface, and it acts as a Python client library for connecting to or embedding Neovim processes. The intended users are Python plugin authors and developers building tools that automate a Neovim session.

The library exposes Neovim objects through a Python-facing API. Built-in and plugin Vimscript functions are available through `nvim.funcs`, while Neovim API functions are available through `vim.api` and through API-bearing objects such as `buffer.api`. Lua functions can be defined with `vim.exec_lua` and called through `vim.lua`. This makes Pynvim useful when a program needs to coordinate editor state with Python data and logic without reproducing Neovim's RPC protocol itself.

Pynvim is not intended to replace Neovim's Lua plugin ecosystem. It is specifically the Python connection layer for users whose implementation language is Python. Its package metadata names Python 3.10 through Python 3.14 as supported versions and requires Python 3.10 or later.

Remote plugins, Vim plugins, and RPC sessions

Pynvim supports both Python remote plugins through Neovim's language-agnostic rplugin interface and Vim plugins through `:python3`. The remote plugin route is the more expressive option described by the README. Such plugins can handle Vimscript function calls, define commands and autocommands, and operate asynchronously without blocking Neovim. Once Pynvim is installed, Neovim reports support for the `+python3` Vim feature.

For library use, Pynvim communicates with Neovim through its msgpack-rpc API. A client can attach to an existing Neovim process by its server address, or it can start a child process with `--embed`. An embedded headless process is useful when Neovim should run without waiting for a user interface. If the Python program is itself a UI, the process can use `--embed` without `--headless`, allowing startup to continue while waiting for `nvim_ui_attach`.

This architecture separates the Python application from the editor process while preserving access to editor state. It is also why Pynvim has responsibilities that a simple syntax parser does not: process attachment, remote calls, object proxies, async requests, and plugin registration.

Installing Pynvim with uv or pipx

The README requires Python 3.10 or later. It recommends `uv` for an isolated command installation. The `--upgrade` option asks the installer to update an existing tool installation.

bash
uv tool install --upgrade pynvim

The README says to rerun this command whenever Neovim is upgraded, so Pynvim and Neovim are expected to move together.

If `pipx` is already available, its installation path is also documented.

bash
pipx install pynvim

For a later Pynvim upgrade through `pipx`, run:

bash
pipx upgrade pynvim

These commands install the package but do not replace the separate `nvim` executable. The REPL and embedded-process examples assume that `nvim` is available through `PATH`.

Connecting to a Neovim socket for a first edit

The simplest documented first use begins by starting Neovim with a known address. This creates the socket that the Python process will attach to.

sh
$ nvim --listen /tmp/nvim.sock

In another terminal, use the Python REPL to import Pynvim and attach to that socket. Once `attach` returns, `nvim` represents the connected Neovim instance.

python
>>> import pynvim
>>> nvim = pynvim.attach('socket', path='/tmp/nvim.sock')
>>> buffer = nvim.current.buffer
>>> buffer[0] = 'replace first line'

The README then demonstrates broader object access. Assigning `buffer[:]` replaces the buffer contents, `nvim.command('vsplit')` runs a Neovim command, and `nvim.windows[1].width = 10` changes a window property. Global variables can be assigned and evaluated through `nvim.vars` and `nvim.eval`.

Embedding Neovim inside a Python application

A Python application does not have to connect to a separately started editor. Pynvim can launch `nvim` as a child process in embedded mode. The README uses `--headless` for a server-style process that does not wait for a UI.

python
>>> import pynvim
>>> nvim = pynvim.attach('child', argv=["/usr/bin/env", "nvim", "--embed", "--headless"])

This is the relevant path for automation, background integrations, and Python programs that own the Neovim lifecycle. The object model remains the same after attachment: the connected instance still exposes its current buffer, commands, windows, variables, and API functions.

The choice between socket attachment and child attachment is operational. Socket attachment suits a client that should connect to an existing editor address. Child attachment suits an application that needs to supply the process arguments and manage the embedded process. The README mentions multiple transports but uses these two approaches for its initial examples; it does not claim that socket and child attachment are the only transports.

The Vimscript dictionary copy limitation

The most concrete limitation is documented by Pynvim and Neovim: Neovim does not support `bindeval`, so a Vimscript dictionary read through `vim.vars`, `vim.vvars`, or `Buffer.vars` is returned as a copy rather than a live reference. Mutating a nested field therefore does not write the change back into Neovim.

This code does not perform the intended update:

python
vim.vars['my_dict']['field1'] = 'value'

The dictionary must instead be read, modified, and assigned as a whole.

python
my_dict = vim.vars['my_dict']
my_dict['field1'] = 'value'
vim.vars['my_dict'] = my_dict

That requirement affects code architecture. A plugin cannot treat every retrieved Vimscript dictionary as a transparent proxy. Code that edits nested dictionaries must construct a new Python value or at least reassign the complete dictionary after modification. For data structures where Neovim-side mutation is frequent, this is a real reason to prefer Python-owned objects or explicit full assignments.

Pynvim against the Vim `:python3` path

The README directly identifies the Vim `:python3` interface as a comparison point. That path is appropriate when the code is already a Neovim Vim plugin, executes inside Neovim, and only needs Python available for that plugin. It does not need an application to create and manage a separate connection just to manipulate the current editor.

Pynvim adds a broader client role. It can attach to a running Neovim process through a socket, launch an embedded process, expose API objects to an external Python application, and provide async requests with thread-safety support. Its remote plugin interface also allows Python plugins to handle Vimscript function calls and define commands and autocommands without blocking Neovim.

The practical distinction is therefore ownership and execution location. Use the `:python3` model for an in-editor plugin whose Python code runs as part of Neovim's plugin loading model. Use Pynvim when a Python application needs an explicit connection, when the editor process must be embedded, or when the same client surface should reach multiple Neovim objects. Pynvim is the heavier choice for simple in-editor scripting because installation and RPC are part of its purpose.

Maintenance, releases, and Apache-2.0

The repository is not archived, but its last push was on 2026-04-10. The recorded releases include Pynvim 0.6.0 on 2025-09-07, 0.5.2 on 2024-11-13, and 0.5.1 on 2024-11-03. The package metadata currently declares `0.6.1.dev0` as a development version. This is evidence of a release history, not a claim about current support for every Neovim release.

The README explicitly couples upgrades: whenever Neovim is upgraded, it says to rerun the Pynvim installation or upgrade command. That creates a maintenance task for deployments that keep Pynvim installed as a tool. Package updates also need to be assessed against the Python version, because `requires-python` is `>=3.10`.

The package is licensed under Apache-2.0. That identifies the declared license, but it is not a substitute for checking how the license applies to a particular distribution, plugin bundle, or integration.

Development checks and repository layout

For local development, the README recommends a virtual environment. Changes must be reinstalled before they take effect, and the test suite should be invoked through `python -m pytest` so the current directory is first on `sys.path`. That detail matters because a globally discoverable `pytest` command could otherwise resolve a different installed version.

The repository also documents isolated checks through `uvx` for tests, linting, and type checking. Those commands are development checks rather than requirements for using Pynvim as a runtime library. Based on the repository layout, the implementation is split across `pynvim/`, `neovim/`, tests, documentation, packaging files, and release scripts. The packaging metadata declares a `pynvim-python` entry point and dependencies on `msgpack`, `greenlet` outside PyPy, and `typing-extensions` on older supported Python versions.

Editorial conclusion

Adopt Pynvim when Python code must control Neovim or implement a remote plugin, especially when asynchronous operation and object access to buffers, windows, API functions, and Vimscript functions matter. Do not choose it for Python 3.9 or earlier, for code that requires live Vimscript dictionary references, or for a plugin that must remain entirely inside Neovim without Python. Before adoption, verify compatibility with the deployed Neovim version, Python 3.10 or later, the chosen installation method, and whether your code relies on mutating a Vimscript dictionary in place. Once those constraints pass, Pynvim is a direct Python interface rather than a general-purpose editor framework.

Frequently asked questions

How do I install Pynvim for Python?

The README supports Python 3.10 or later and recommends installing it with `uv tool install --upgrade pynvim`. It also documents `pipx install pynvim` as an alternative.

How can I connect Pynvim to a running Neovim instance?

Start Neovim with a known address, such as `nvim --listen /tmp/nvim.sock`, then use `pynvim.attach('socket', path='/tmp/nvim.sock')` from Python. The README also documents attaching with the `v:servername` address of a running instance.

Can Pynvim start Neovim as an embedded child process?

Yes. The documented example uses `pynvim.attach('child', argv=["/usr/bin/env", "nvim", "--embed", "--headless"])`. Remove `--headless` when the client is a UI and should wait for `nvim_ui_attach`.

Why does changing a Vimscript dictionary field not update Neovim?

Neovim does not support `bindeval`, so dictionaries accessed through Pynvim are copies rather than live references. Read the dictionary, modify the Python value, and assign the complete dictionary back.

Official sources

  1. License: Apache-2.0
  2. neovim/pynvim on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/neovim-pynvim.svg)](https://hysenlabs.com/projects/neovim-pynvim)

Was this useful?