---
title: "How to Install Python on Mac, Upgrade It & Use VENV (2026)"
description: "Step-by-step guide to install Python on Mac using Homebrew, upgrade to the latest version, and set up a Python virtual environment (venv) for your projects."
date: 2026-07-29
categories: ["tools"]
tags: ["python","homebrew","venv"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";

If you've tried to `pip install` something on a Mac recently, you've hit the `externally-managed-environment` error. Since Python 3.12, Homebrew follows PEP 668, which means virtual environments are no longer optional. They're mandatory. This guide walks you through how to install Python on Mac using Homebrew, configure your PATH so `python` works, upgrade between versions without breaking things, and set up venv properly for your projects.

<Notice type="info" title="Updated for 2026">
Python 3.14 is the current stable release (released October 2025). Homebrew's default `python` formula now installs 3.14.x. PEP 668 is enforced for all Homebrew Python 3.12+ builds. `pip install` outside a venv will fail by design.
</Notice>

## Before you begin: prerequisites

### Check your macOS version and architecture (Apple Silicon vs Intel)

Homebrew installs to different locations depending on your Mac's processor:

| Mac type | Homebrew prefix | Python binary path |
|----------|----------------|-------------------|
| Apple Silicon (M1/M2/M3/M4) | `/opt/homebrew/` | `/opt/homebrew/bin/python3` |
| Intel | `/usr/local/` | `/usr/local/bin/python3` |

Check which you have:

```bash
uname -m
```

- `arm64` → Apple Silicon
- `x86_64` → Intel

<Notice type="info" title="Apple Silicon vs Intel">
All commands in this guide use Apple Silicon paths (`/opt/homebrew/`). If you're on Intel, substitute `/usr/local/` where applicable. The commands themselves (`brew install`, `python3`, etc.) are identical.
</Notice>

If you want a better terminal experience before diving in, consider setting up [a modern Mac development terminal](/ghostty-terminal/) first.

### Install Xcode Command Line Tools

macOS ships with its own Python 3 (installed via Xcode Command Line Tools, typically 3.9.x). You need the CLT for Homebrew to work, but **do not remove the system Python**. macOS tools depend on it.

```bash
xcode-select --install
```

Click "Install" in the dialog. This takes a few minutes.

Verify it installed:

```bash
xcode-select -p
```

Expected output: `/Library/Developer/CommandLineTools`

<Notice type="warning" title="Don't remove system Python">
macOS uses its built-in Python 3 for system tools and scripts. Homebrew installs alongside it, not over it. Never delete or modify `/usr/bin/python3`.
</Notice>

### Install Homebrew on Mac

Homebrew is the package manager that makes Python installation simple. If you don't have it yet:

```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```

On Apple Silicon, Homebrew adds its PATH entry to `~/.zprofile` automatically. Follow the post-install instructions shown in the terminal. You may need to run:

```bash
eval "$(/opt/homebrew/bin/brew shellenv)"
```

Verify Homebrew is healthy:

```bash
brew doctor
```

Expected: `Your system is ready to brew.`

If you're customizing your shell, [supercharge your Zsh terminal](/best-oh-my-zsh-plugins/) with useful plugins and [enable syntax highlighting in Zsh](/enable-syntax-highlighting-zsh/) for a better experience.

## Install latest Python on Mac with Homebrew

With Homebrew ready, install the latest stable Python:

```bash
brew install python
```

This installs Python 3.14.x (the current stable release as of 2026), along with `pip`, `setuptools`, and `wheel`.

### Verify your Python installation

Run these checks to confirm everything is working:

<ListCheck>
<ul>
<li><code>python3 --version</code> → should show <code>Python 3.14.x</code></li>
<li><code>which python3</code> → should show <code>/opt/homebrew/bin/python3</code> (Apple Silicon)</li>
<li><code>which pip3</code> → should show <code>/opt/homebrew/bin/pip3</code></li>
<li><code>python --version</code> → works after PATH configuration (see next section)</li>
</ul>
</ListCheck>

```bash
python3 --version
which python3
which pip3
```

Expected output:

```sh
Python 3.14.6
/opt/homebrew/bin/python3
/opt/homebrew/bin/pip3
```

### Configure your PATH for Python on Mac

Here's the thing nobody tells you: after `brew install python`, the command `python3` works, but `python` does NOT. You'll get:

```sh
zsh: command not found: python
```

Homebrew installs the unversioned symlinks (`python`, `pip`) to a separate directory that's not on your PATH by default. Fix it:

```bash
# Add Homebrew Python's unversioned commands to PATH
echo 'export PATH="$(brew --prefix python)/libexec/bin:$PATH"' >> ~/.zprofile
source ~/.zprofile
```

<Notice type="warning" title="`python` command not found?">
This is expected before PATH configuration. The fix is the `export PATH` line above. Add it to `~/.zprofile` (for login shells) or `~/.zshrc` (for interactive shells). Either works in Terminal.app.
</Notice>

Verify:

```bash
python --version
```

Should show the same version as `python3 --version`.

## Install a specific Python version on Mac

Sometimes a project requires a specific Python version. Homebrew provides versioned formulae for this.

### How to search for available Python versions in Homebrew

```bash
brew search python@
```

You'll see entries like `python@3.9` through `python@3.14`. For the live, up-to-date list with exact version numbers:

<Button text="View all Python formulae on Homebrew" link="https://formulae.brew.sh/formula/" variant="outline" color="blue" size="sm" />

Install the version you need. For example, Python 3.13:

```bash
brew install python@3.13
```

The versioned command works immediately after install:

```bash
python3.13 --version
```

```sh
Python 3.13.14
```

No linking required. You can use `python3.13` directly in your commands and virtual environments.

### Linking keg-only Python formulae

Versioned Python formulae (like `python@3.13`) are "keg-only." Homebrew does not symlink them into your PATH by default. If you try to `brew link` one and another Python version is already linked, you'll get an error:

```sh
Error: Cannot link python@3.13
```

If you actually need `python3` to point to a different version:

```bash
# Unlink the current version first
brew unlink python

# Link the version you want
brew link --force python@3.13
```

<Notice type="warning" title="Relinking changes `python3` globally">
After `brew link --force python@3.13`, the `python3` command will point to 3.13 instead of 3.14. This affects all your terminal sessions. In most cases, it's simpler to just use the versioned command (`python3.13`) and skip relinking entirely.
</Notice>

## Upgrade Python to the latest version on Mac

This is where most guides get it wrong, including the previous version of this article.

### The truth about `brew upgrade python` (major vs patch upgrades)

`brew upgrade python` does **not** jump between major versions. It upgrades to the latest **patch** of whatever formula you have installed.

```bash
# Update Homebrew's package index
brew update

# Upgrade to latest patch of current formula (e.g., 3.14.5 to 3.14.6)
brew upgrade python
```

Verify:

```bash
python3 --version
```

<Notice type="warning" title="Major vs patch upgrades">
<code>brew upgrade python</code> will NOT upgrade from Python 3.13 to 3.14. To switch major versions, you must <code>brew install python@3.14</code> explicitly. This is the #1 misconception about upgrading Python with Homebrew.
</Notice>

To jump from one major version to another:

```bash
# Install the new major version
brew install python@3.14

# Use it with the versioned command
python3.14 --version
```

### Pin Python to prevent accidental upgrades

When Homebrew upgrades other packages, it can sometimes upgrade Python as a dependency. This changes the Python binary path, which **breaks existing virtual environments**. Pin your Python version to prevent this:

```bash
# Pin prevents accidental upgrades
brew pin python@3.14

# Check what's pinned
brew list --pinned

# Unpin when you're ready to upgrade
brew unpin python@3.14
```

<Accordion label="Why did my virtual environment break?" group="faq">
When Homebrew upgrades Python (even a patch version), it can change the absolute path to the Python binary inside your `.venv`. Since venvs store absolute paths in `pyvenv.cfg` and inside the activate scripts, the old venv may stop working after an upgrade.

Fix: recreate the venv and reinstall dependencies.

```bash
rm -rf .venv
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

Prevention: use `brew pin` on your Python formula.
</Accordion>

## Understanding PEP 668: why you need virtual environments

This is the section I wish existed when I first ran into the error. If you've tried to install a Python package globally with pip and gotten a wall of red text, here's why.

### The `externally-managed-environment` error explained

Starting with Python 3.12, Homebrew marks its Python installation as "externally managed" (per [PEP 668](https://peps.python.org/pep-0668/)). This means:

```bash
pip install requests
```

Results in:

```
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try brew install
    xyz, where xyz is the package you are trying to install.
```

This is **not a bug**. It's a deliberate protection. Homebrew Python is managed by Homebrew. Letting pip install packages globally could conflict with Homebrew-managed packages and break your system.

The fix: use a virtual environment (for project dependencies) or `pipx` (for CLI tools). Both are covered in the next sections.

<Notice type="error" title="`externally-managed-environment` error?">
This is expected behavior since Python 3.12, not a mistake. Activate a virtual environment before using <code>pip install</code>, or use <code>pipx</code> for global CLI tools. See the next sections for both approaches.
</Notice>

Reference: [Homebrew and Python](https://docs.brew.sh/Homebrew-and-Python) documentation.

## Run Python in VENV on Mac

Virtual environments are now the standard (and required) way to manage Python project dependencies. Here's the full workflow.

### Create a Python virtual environment on Mac

Navigate to your project directory and create a venv:

```bash
cd ~/my-project
python3 -m venv .venv
```

<Notice type="info" title="Why `.venv`?">
<code>.venv</code> is the modern convention. It's what VS Code, PyCharm, uv, and Poetry auto-detect. It's hidden by default on macOS (the leading dot), and it's the name you'll see in most Python projects on GitHub. You can use a custom name if you prefer, but <code>.venv</code> is the default for a reason.
</Notice>

### Activate and use your virtual environment

```bash
source .venv/bin/activate
```

Your terminal prompt changes to show the active environment:

```sh
(.venv) user@mac my-project %
```

Verify it's working:

```bash
which python
```

Should show: `/Users/youruser/my-project/.venv/bin/python`

Now `pip install` works without PEP 668 errors:

```bash
pip install requests
```

### Install packages and freeze requirements

This is the practical workflow that was missing from the old article:

```bash
# Install packages inside your active venv
pip install requests pandas fastapi

# Freeze current dependencies to a file
pip freeze > requirements.txt
```

The `requirements.txt` file lets anyone recreate the same environment:

```bash
# On another machine (or after cloning a repo):
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

<Accordion label="Using uv instead of pip?" group="faq">
`uv` is a drop-in replacement for pip that's 10-100x faster. Install it with `brew install uv` and use:

```bash
uv pip install requests pandas
uv pip freeze > requirements.txt
uv venv  # creates venvs faster than python -m venv
```

For a full walkthrough, see [uv, a modern Python package manager](/uv-get-start/).
</Accordion>

### Deactivate the virtual environment

When you're done working:

```bash
deactivate
```

Your prompt returns to normal. The packages stay installed in `.venv/`. Nothing is lost.

### Add `.venv` to `.gitignore`

Never commit your virtual environment to git. Add these entries to your `.gitignore`:

```
.venv/
venv/
env/
```

<ListCheck>
<ul>
<li>Add <code>.venv/</code> to <code>.gitignore</code></li>
<li>Add <code>venv/</code> and <code>env/</code> as well (common alternatives)</li>
<li>Commit <code>requirements.txt</code> instead of the venv directory</li>
<li>GitHub's default Python <code>.gitignore</code> template already includes these</li>
</ul>
</ListCheck>

## Troubleshooting common Python on Mac issues

<Accordion label="Fix: `python` command not found" group="troubleshooting" expanded="true">
**Cause**: Homebrew doesn't add `python` (unversioned) to your PATH by default.

**Fix**:

```bash
echo 'export PATH="$(brew --prefix python)/libexec/bin:$PATH"' >> ~/.zprofile
source ~/.zprofile
python --version
```

In the meantime, `python3` always works after `brew install python`.
</Accordion>

<Accordion label="Fix: `brew link` fails for versioned Python" group="troubleshooting">
**Cause**: Versioned Python formulae are keg-only. Another Python version is already linked.

**Fix**: Use the versioned command directly instead of relinking:

```bash
# Just use the versioned command. No linking needed.
python3.13 --version
python3.13 -m venv .venv
```

If you must relink:

```bash
brew unlink python
brew link --force python@3.13
```
</Accordion>

<Accordion label="Fix: `externally-managed-environment` error" group="troubleshooting">
**Cause**: You're running `pip install` outside a virtual environment. PEP 668 blocks this with Homebrew Python 3.12+.

**Fix**: Activate a venv first:

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install <package>
```

For global CLI tools (black, ruff, mypy), use `pipx` instead:

```bash
brew install pipx
pipx ensurepath
pipx install black
```
</Accordion>

<Accordion label="Fix: broken venv after `brew upgrade`" group="troubleshooting">
**Cause**: Homebrew upgraded Python, changing the binary path that your venv references.

**Fix**: Recreate the venv:

```bash
rm -rf .venv
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

**Prevention**: Pin your Python version with `brew pin python@3.14`.
</Accordion>

## Alternatives to consider

Homebrew is the simplest path, but it's not the only one. Here are the main alternatives.

### uv: a modern Python package manager

`uv` by Astral is an all-in-one Python tool that replaces pip, venv, pyenv, and pipx. It's written in Rust and significantly faster than pip.

```bash
brew install uv
uv venv           # create venvs faster
uv pip install requests  # drop-in pip replacement
uv python install 3.13   # install specific Python versions
```

If you want a single tool that handles everything covered in this article, `uv` is worth a look. Full guide: [uv, a modern Python package manager](/uv-get-start/). For deployment: [deploy a Python project with uv and Dokploy](/dokploy-python-railpack-uv/).

### pyenv: manage multiple Python versions

[pyenv](https://github.com/pyenv/pyenv) is for when you need to switch between Python versions frequently across different projects. Homebrew's own docs recommend it "if you require stability of minor or patch versions for virtual environments."

```bash
brew install pyenv
pyenv install 3.13.14
pyenv install 3.14.6
pyenv global 3.14.6
```

pyenv manages versions independently of Homebrew, so upgrading Homebrew won't accidentally change your project's Python version. More overhead to set up, but more control.

### Official Python.org installers

Python.org provides [macOS universal2 installers](https://www.python.org/downloads/macos/) that work on both Apple Silicon and Intel. These are standalone, no Homebrew dependency.

Use this if you don't want Homebrew at all, or if you need a specific Python build. The downside: manual PATH setup, no automatic updates, and it doesn't integrate with the Homebrew ecosystem.

### pipx: install Python CLI tools globally

`pipx` installs Python CLI tools (like `black`, `ruff`, `mypy`, `poetry`) in isolated environments, making them available globally without polluting your system Python.

```bash
brew install pipx
pipx ensurepath
pipx install black
pipx install ruff
```

<Notice type="info" title="pipx vs venv">
<strong>pipx</strong> is for CLI tools you run from anywhere (formatters, linters, build tools). <strong>venv</strong> is for project dependencies your code imports. They solve different problems and work well together.
</Notice>

## Next steps: what to build with Python on Mac

Now that you have Python installed and know how to manage environments, here's where to go from here:

- [Explore the best Python web frameworks](/best-python-web-frameworks/): find the right framework for your next project
- [Build a UI for your Python app with NiceGUI](/nicegui-get-started/): quick-start guide for Python UI apps
- [Add multiple pages to your NiceGUI app](/nicegui-pages/): follow-up for NiceGUI projects
- [Run your Python app in Docker](/docker-run-python/): containerize your project for consistent deployments
- [Deploy a Python project with uv and Dokploy](/dokploy-python-railpack-uv/): production deployment on a VPS
- [Generate AI images locally with Python](/ai-images-mac/): run Flux models on your Mac

If you're deploying to a server, [Hetzner](https://go.bitdoze.com/hetzner) offers affordable EU VPS that works well for Python apps.

<Button text="Browse All Python Tutorials" link="/tags/python/" variant="solid" color="blue" size="md" icon="arrow-right" />