Open-source project
linux-cultist/venv-selector.nvim avatar
linux-cultist/venv-selector.nvim

venv-selector.nvim finds your Python environment and switches it inside Neovim

Allows selection of python virtual environment from within neovim

774 stars74 forksLuaMIT

At a glance

What is it?
venv-selector.nvim is a Lua plugin that discovers Python virtual environments from standard Python, Poetry, Pipenv, Conda, Pyenv, Hatch, Pipx and PEP-723 sources, then activates the one you pick without restarting Neovim. It also rewires the LSP to use the selected interpreter and exports the environment to terminals you spawn from the editor.
Who is it for?
Adopt venv-selector.nvim if you work across several Python projects in one Neovim session and keep re-activating environments by hand, since the plugin remembers the environment per workspace and applies it to the LSP and to terminals. Skip it if you run a single project with a single environment, or if you cannot install fd, since the default searches depend on it.
Can I use it commercially?
Yes. MIT 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?
Yes. The repository last received commits 156 days ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

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

Editorial analysis

One picker call replaces the activate-this-venv ritual

The plugin's job is small and specific: discover Python virtual environments and let you switch between them from inside Neovim, with no restart required.

The quick start is six steps. Add the plugin to your plugin manager. Open any Python file. Trigger `:VenvSelect` or your mapped key, which the example maps to `,v`. Choose a virtual environment. Optionally open Python files in other projects and repeat. And then you can switch between their buffers, because the plugin remembers the selected venv for each project.

That last point is the feature that makes it more than a convenience wrapper. The plugin caches the last selected venv per workspace and re-activates it when you open files in the same workspace, so the mental model is one environment per project rather than one environment per Neovim session.

The plugin also configures your LSP to use the selected venv, and sets `VIRTUAL_ENV` or `CONDA_PREFIX` for use in terminals started from Neovim. That second part is what stops the classic mismatch where the editor's language server is right but the terminal you open from it is running the system Python.

The scope of the tool is worth stating clearly, because the FAQ is explicit about it. It will not change your system Python. It only sets environment variables within Neovim and spawned child processes. And you do not need to restart Neovim after switching venvs, because activation is done in-process and new terminals opened after the selection inherit the environment.

The project is Lua, MIT licensed, and the last push was on 2026-05-20 with no GitHub releases.

The default searches cover most environment managers

The discovery mechanism is where the practical value lies, because Python environment management is fragmented.

The plugin searches for virtual environments automatically in common places and in your workspaces, and the list of what it recognises is long. Plain Python, created with `python3 -m venv venv`. Poetry. Pipenv. Anaconda. Miniconda. Pyenv, including the pyenv-virtualenv and pyenv-win-venv plugins. Virtualenvwrapper. Hatch. And Pipx.

The detection method is described in the FAQ: the plugin searches for interpreter binaries and recognises common venv manager locations. That is a different approach from asking each manager where its environments live, and it means a manager it has never heard of still works if it puts an interpreter somewhere recognisable.

PEP-723 metadata is supported if `uv` is available, and that integration is called out separately in the feature list as its own item, with a link to the usage documentation. PEP 723 is the inline script metadata standard, so a Python file that declares its own dependencies can point at the environment it wants.

If your environment is somewhere the default searches do not cover, you can add your own searches, and the documentation has a section on creating them with examples. The `search` key in the plugin options takes custom search definitions, which is a config-level escape hatch rather than a code change.

One hard requirement underpins the default searches: `fd` or `fdfind` is required. The plugin uses it to walk the filesystem quickly, and the documentation lists it as a requirement rather than a recommendation.

The plugin spec is small because the plugin is lazy by design

The installation example is a lazy.nvim spec, and it is worth reading closely for what it does and does not configure.

lua
{
  "linux-cultist/venv-selector.nvim",
  dependencies = {
    { "nvim-telescope/telescope.nvim", version = "*", dependencies = { "nvim-lua/plenary.nvim" } }, -- optional: you can also use fzf-lua, snacks, mini-pick instead.
  },
  ft = "python", -- Load when opening Python files
  keys = { { ",v", "<cmd>VenvSelect<cr>" }, }, -- Open picker on keymap
  opts = {
    options = {}, -- plugin-wide options
    search = {}   -- custom search definitions
  },
}

The `ft = "python"` field means the plugin is lazy-loaded and only activates when you open a Python file, which is the right behaviour for a tool that only matters in Python projects. The keymap is a single command binding.

The `opts` table has exactly two keys, `options` for plugin-wide options and `search` for custom search definitions, which shows how little the plugin insists on.

The telescope dependency is marked optional, and the picker backends are the interesting part. The plugin supports `telescope`, `fzf-lua`, `snacks`, `mini-pick` and `vim.ui.select`, the last being the one built into Neovim itself. That means you can use the plugin with no picker plugin at all, using the plain select dialog, which is a meaningfully lower setup cost than it first appears.

The documentation is split into three files after installation: USAGE for the features, API for interacting with the plugin from Lua, and OPTIONS for configuration.

Two commands exist mainly for debugging the plugin

Two of the plugin's commands are diagnostic, and knowing when they are available saves confusion.

`:VenvSelectLog` is available if you set the `log_level` option to `DEBUG` or `TRACE`, and it shows a detailed log of what the plugin is doing when you pick a virtual environment in the picker. The troubleshooting guidance is to start with that log level and then use the command after using `:VenvSelect`, and to open an issue with the `:VenvSelectLog` output and your search config if problems persist.

`:VenvSelectCache` is available only if the `cached_venv_automatic_activation` option is `false`. That means you have turned off automatic activation of cached venvs, and the command lets you activate them from cache manually. So the command appears precisely when the automatic behaviour has been disabled, and it is the escape hatch for that case.

The logging configuration is a one-liner:

lua
{
  options = {
    log_level = "TRACE" -- enable VenvSelectLog command
  }
}

A plugin that manipulates environment variables for your editor, your language server and every terminal you open deserves a debug log, and the fact that the log is gated behind an option rather than always on is the right default.

The integration surface is broader than just the picker. The plugin integrates with debuggers through nvim-dap, nvim-dap-python and debugpy, and with statuslines, with Lualine and NvChad having specific support documented. It also works with many pickers. A Nerd Font is listed as an optional requirement, needed for icons in certain pickers and statuslines.

The 0.11 requirement came with a change in who configures the LSP

The recent major updates list is short and each entry is a compatibility decision rather than a feature.

On 2025-09-30 the minimum Neovim became 0.11, and the important part of that entry is the second clause: LSP servers are expected to be configured by the user via `vim.lsp.config`. That is a change in responsibility, not just a version bump. The plugin sets up the environment the LSP server runs in, and the server definition itself is now yours to declare through the newer Neovim API.

On 2026-02-16 two things landed. An LSP gate was added to prevent concurrent LSP operations, described as stop/start races. And support for switching between multiple Python projects and PEP-723 `uv` metadata files was added, along with remembering the venv for each.

The race condition is worth understanding rather than just noting. When you switch the environment, the language server has to be restarted against a different interpreter, and a stop of one server and a start of another can overlap. A gate serialises those operations so they cannot interleave. The symptom without it would be a language server that fails to start or that keeps pointing at the old environment, which is exactly the kind of intermittent problem that is hard to attribute.

The 2025-08-27 entry records a branch change. The regexp branch was merged into `main`, and if you need the older behaviour you can pin the `v1` branch, with the note that `v1` is no longer actively updated. That is a migration note for anyone who had pinned a branch, and it is a reminder that the current behaviour is the newer one.

Where this sits against a manual environment switch

The comparison worth making is with what you would do without the plugin, because the alternative is not another plugin.

The manual version is a shell command you run before starting Neovim, or an activation line you source in your shell configuration, or a directory-based approach where a .envrc or a direnv setup changes the environment when you cd into a project. Each works, and each has the same weakness in an editor context: the environment is fixed when the editor starts, so working on a second project means either a second editor instance or an environment that is wrong for one of the two.

venv-selector.nvim's contribution is that it makes the environment a property of the open buffer rather than of the process. You can have a file from project A and a file from project B open in the same Neovim, and the plugin tracks the right environment for each, applies it to the LSP for each, and hands the correct environment to a terminal opened from each.

The cost is a dependency on the environment manager's on-disk layout rather than its API, plus a filesystem scan. The plugin needs fd for the search, and the search covers a set of well-known locations, so an environment in an unusual place needs a custom search definition. The documentation is upfront that you may need to add your own searches if your expected venvs do not appear in the picker.

The requirements list is the full price: Neovim 0.11 or newer, fd or fdfind for the default searches, and a picker plugin, with the debugger integration and nvim-notify both optional.

Editorial conclusion

Adopt venv-selector.nvim if you work across several Python projects in one Neovim session and keep re-activating environments by hand, since the plugin remembers the environment per workspace and applies it to the LSP and to terminals. Skip it if you run a single project with a single environment, or if you cannot install fd, since the default searches depend on it. Verify first that your Neovim is 0.11 or newer, that you are on the main branch rather than the pinned v1 branch, and that your environment manager is one of the ones the default searches cover, or that you are prepared to write a custom search definition.

Frequently asked questions

How do I select a Python virtual environment in venv-selector.nvim?

Open a Python file, trigger `:VenvSelect` or the mapped key, and choose an environment from the picker. The plugin then configures the LSP to use it and sets `VIRTUAL_ENV` or `CONDA_PREFIX` for terminals started from Neovim.

Which Python environment managers does venv-selector.nvim detect?

Plain Python venvs, Poetry, Pipenv, Anaconda, Miniconda, Pyenv including the pyenv-virtualenv and pyenv-win-venv plugins, Virtualenvwrapper, Hatch and Pipx. PEP-723 metadata is supported when `uv` is available, and you can define your own searches if your environment is somewhere else.

Does switching venvs in venv-selector.nvim affect my system Python?

No. The plugin only sets environment variables within Neovim and in the child processes it spawns, and activation happens in-process, so no Neovim restart is needed. New terminals opened after the selection inherit the environment.

What are the requirements for venv-selector.nvim?

Neovim 0.11 or newer, and `fd` or `fdfind` for the default searches. A picker plugin is needed, and the supported backends are telescope, fzf-lua, snacks, mini-pick and vim.ui.select. Debugger integration needs nvim-dap, nvim-dap-python and debugpy, and a Nerd Font is optional for icons.

Official sources

  1. Issues
  2. License: MIT
  3. linux-cultist/venv-selector.nvim on GitHub
  4. README
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/linux-cultist-venv-selector-nvim.svg)](https://hysenlabs.com/projects/linux-cultist-venv-selector-nvim)

Was this useful?