Poetry solves a real problem — reproducible Python dependency management with a proper lockfile — but it solves it by creating a full virtual environment per project, and it is easy to lose track of how many of those you have accumulated once you've worked on a few dozen Python projects over a couple of years. Here is where Poetry puts everything on macOS and how to clear out what you don't need.

Where Poetry stores virtualenvs by default

Unless you have configured otherwise, Poetry creates virtual environments in a central location rather than inside each project: ~/Library/Caches/pypoetry/virtualenvs/ on macOS. Each project gets its own subfolder here, named after the project plus a hash, something like myproject-a1B2c3D4-py3.11. That naming makes it easy to end up with several folders for the same project if you have renamed it, changed Python versions, or recreated the environment over time — Poetry does not automatically clean up the old one when that happens.

Alongside the virtualenvs folder, ~/Library/Caches/pypoetry also holds Poetry's package cache (downloaded and built artefacts, similar in purpose to pip's or uv's cache) in a separate cache subdirectory.

Listing what you actually have

Before deleting anything, see what Poetry currently knows about for the project you're in:

poetry env list

This shows every virtualenv Poetry has associated with the current project (there can be more than one if you've switched Python versions). To see the full path of the active one:

poetry env info --path

For a global inventory of everything under ~/Library/Caches/pypoetry/virtualenvs/, there is no single Poetry command — you have to actually look at the folder:

ls -la ~/Library/Caches/pypoetry/virtualenvs/
du -sh ~/Library/Caches/pypoetry/virtualenvs/*

This is usually the moment people realise how many of these have piled up, especially for projects that were cloned, tried, and abandoned.

Removing a specific virtualenv

poetry env remove <python-version-or-name>

Run inside the project directory, this removes the environment tied to that project (or a specific Python version's environment, if a project has several). Poetry also accepts poetry env remove --all to remove every environment associated with the current project in one go.

If a project has already been deleted from disk but its virtualenv is still sitting in the central cache, you don't need the project directory to exist — you can delete the specific environment folder directly from ~/Library/Caches/pypoetry/virtualenvs/, since it's just a normal Python virtualenv on disk once Poetry has created it. Poetry will simply recreate it (or a fresh one) the next time you run poetry install inside that project, if the project still exists.

In-project virtualenvs: a different, more visible layout

Poetry supports a configuration option that changes this behaviour entirely:

poetry config virtualenvs.in-project true

With this set, Poetry creates the virtualenv inside the project itself, as a .venv folder next to pyproject.toml, rather than in the central cache. This has two practical effects worth knowing:

  • It is easier to find and clean up — deleting the project folder deletes its virtualenv along with it, no orphaned entries left behind in a central cache you have to remember to check.
  • It is easier for editors to detect — many IDEs auto-discover a .venv folder in the project root, whereas a centrally-stored venv sometimes needs to be pointed to manually.

The tradeoff is that in-project virtualenvs are more visible to accidental inclusion in version control if .gitignore doesn't already exclude .venv (most Python .gitignore templates do), and they don't benefit from any sharing Poetry might otherwise do across projects using an identical dependency set — though in practice Poetry does not share virtualenv contents across projects either way; each one is a full, independent install.

Why the central store grows the way it does

Every combination of project and Python interpreter version gets its own full virtualenv, and each virtualenv contains a complete copy of every dependency — not a symlink or a shared reference. A project with numpy, pandas, and torch might carry a virtualenv well over a gigabyte, and if you've run poetry install against three different Python versions for the same project while debugging a compatibility issue, that's three multi-gigabyte folders sitting in the cache simultaneously.

This is the single biggest space consumer in a typical Poetry-based development history — bigger, usually, than the package cache itself, because the cache at least deduplicates identical wheel versions across projects, while virtualenvs never do.

Multiple Python versions multiply the problem

If you rely on pyenv alongside Poetry to manage multiple Python interpreter versions, be aware that Poetry creates a distinct virtualenv for each interpreter version a project has been built against, even if the project itself hasn't changed. Debugging a compatibility issue by testing a project against Python 3.10, 3.11, and 3.12 in turn — a common step when investigating why a dependency behaves differently across versions — leaves three full virtualenvs behind in the central cache once you've moved on, one per version tested, none of them automatically cleaned up when you settle on a final version to use going forward.

poetry env list --full-path shows every environment tied to the current project, including ones for interpreter versions you're no longer using, which is the fastest way to spot this pattern before it accumulates across many projects simultaneously.

Configuration drift between machines

One further wrinkle worth knowing: the virtualenvs.in-project setting is a Poetry configuration value, not something recorded in the project itself, so a team where some developers have it enabled and others don't will see genuinely different behaviour from the same repository — one developer's clone gets a .venv folder inside the project, another's gets an entry in the central cache, and neither is wrong. If you're auditing disk usage across a shared project, this explains why the same repository can look completely different in terms of where its virtualenv actually lives from one teammate's Mac to the next.

A practical cleanup pass

  1. du -sh ~/Library/Caches/pypoetry/virtualenvs/* to see every environment and its size, sorted or eyeballed for the largest offenders.
  2. For each one tied to a project you still use, decide whether you actually need it right now, or whether poetry install next time you open the project is an acceptable cost to reclaim the space today.
  3. For folders tied to projects that no longer exist on disk, delete them directly — there is nothing left to regenerate them from except recreating the project.
  4. Separately check ~/Library/Caches/pypoetry/cache (the package cache, distinct from virtualenvs) — poetry cache clear --all . clears it, prompting per cache pool unless you pass --no-interaction.
  5. If you're migrating a project to in-project virtualenvs going forward, remove its old central-store copy once the new .venv is confirmed working.

Where VolumeLens fits in

A handful of forgotten Poetry virtualenvs, each a full gigabyte-plus copy of a dependency tree, is exactly the kind of thing that hides inside ~/Library/Caches where nobody looks until the disk is nearly full. VolumeLens maps your entire disk visually, so ~/Library/Caches/pypoetry/virtualenvs shows up sized honestly next to everything else, with each project's environment visible as its own folder rather than one opaque blob. See how it works before your next poetry install surprises you with a "no space left on device" error.