Trying to run a Python GUI app on a Mac often ends in ModuleNotFoundError: No module named '_tkinter'.
There is essentially one cause: Homebrew ships Python and tkinter as separate packages — and separate packages per Python minor version.
So the fix is equally specific. Check which Python version you are running and install the matching python-tk@X.Y. In most cases that is the entire solution.
This article was published in 2025 and revised in September 2026. The original listed installing tcl-tk and setting environment variables as required steps. Normally they are not needed. After re-testing on my own Mac, this version separates the cases where they are from the cases where they are not.
Sponsored
First, check your Python version
Copying commands without checking this is why the problem drags on.
python3 -V
Python 3.14.6
In this case you need python-tk@3.14. Installing the 3.13 package will not be loaded by 3.14.
Check which Python is actually running as well.
which -a python3
/Users/you/project/.venv/bin/python3 <- virtual environment
/opt/homebrew/bin/python3 <- Homebrew
/Users/you/.pyenv/shims/python3 <- pyenv
/usr/bin/python3 <- macOS system
Having several Pythons side by side is the single biggest reason this problem persists. The first match wins, so find out which one you are currently using.
Reproducing the error, and why it happens
Running this on Python 3.14 without python-tk installed gives:
python3 -c "import tkinter"
ModuleNotFoundError: No module named '_tkinter'
Note that it is _tkinter, not tkinter, that is missing. The Python-level tkinter package is present; what is absent is the C extension module _tkinter underneath it.
Homebrew's Python is built without tkinter on the assumption that most users do not need a GUI. Adding python-tk is left to the people who do.
Sponsored
Fix 1: install python-tk (this solves almost every case)
Install the version that matches.
# if you are on Python 3.14
brew install python-tk@3.14
# for 3.13
brew install python-tk@3.13
brew search python-tk lists what is available.
brew search python-tk
python-tk@3.9 python-tk@3.10 python-tk@3.11
python-tk@3.12 python-tk@3.13 python-tk@3.14
Verify after installing.
python3 -c "import tkinter; print(tkinter.TkVersion)"
9.0
A version number means it worked. To confirm with an actual window:
python3 -m tkinter
A small window should open.
You do not need to install tcl-tk separately. python-tk pulls it in as a dependency. Environment variables are normally unnecessary too.
Fix 2: rebuild the virtual environment
If installing python-tk did not help, the virtual environment may be the reason.
venv references the Python it was created from, so installing python-tk afterwards may not be reflected in an existing environment.
# check outside the virtual environment
deactivate
python3 -c "import tkinter; print('OK')"
# if it works outside, rebuild the environment
rm -rf .venv
python3 -m venv .venv
source .venv/bin/activate
python3 -c "import tkinter; print('OK')"
"Works outside the venv, fails inside" is almost always this.
Sponsored
Fix 3: if you use pyenv
pyenv is a different situation. It builds Python from source, so if tcl-tk is not found at build time, you end up with a Python that has no tkinter.
Installing python-tk afterwards will not fix that. You have to install tcl-tk first and rebuild Python.
# install tcl-tk first
brew install tcl-tk
# reinstall Python, pointing the build at tcl-tk
env PYTHON_CONFIGURE_OPTS="--with-tcltk-includes=$(brew --prefix tcl-tk)/include --with-tcltk-libs='-L$(brew --prefix tcl-tk)/lib -ltcl9.0 -ltk9.0'" pyenv install 3.13.0
The version numbers in the library names (tcl9.0 / tk9.0) vary by environment. Check before specifying them.
ls $(brew --prefix tcl-tk)/lib | grep -E "libtcl|libtk"
Building it yourself is the only case where environment variables genuinely matter. Using Homebrew's Python as-is does not need them.
Fix 4: the system Python, if you just need it working now
The Python that ships with macOS has tkinter.
/usr/bin/python3 -c "import tkinter; print(tkinter.TkVersion)"
8.5
It is not recommended for everyday use, for three reasons:
- The Tk version is old (8.5, versus 9.0 on the Homebrew build)
- A macOS update can change or remove it
- It lives in system space, so you cannot install packages freely
Treat it as a way to confirm something works right now, nothing more.
Reinstalling Homebrew is a last resort
The original version of this article suggested uninstalling and reinstalling Homebrew's Python. That has far too wide a blast radius.
Other packages that depend on Python get caught in it, so consider it only after everything above has failed.
These are worth checking first.
# check for broken links
brew doctor
# confirm python-tk is actually installed
brew list | grep python-tk
Order of diagnosis
When in doubt, work through this in order.
| What to check | Command | What it tells you |
|---|---|---|
| 1. Python version | python3 -V |
Install the matching python-tk@X.Y |
| 2. Which Python | which -a python3 |
If pyenv, go to Fix 3 |
| 3. Does it work outside the venv? | deactivate and retest |
If yes, rebuild the venv |
| 4. Just need it running | /usr/bin/python3 |
Temporary confirmation only |
Actually building a GUI tool
Once tkinter works, you can build something with it. I built a pairwise test case generator.
pip install allpairspy pandas
- allpairspy: generates pairwise test cases
- pandas: data handling, including CSV output
The build is written up in the pairwise test generator GUI tool I made for Mac. For the technique itself, see the basics and practice of pairwise testing.
Summary
- The cause is that Homebrew keeps Python and tkinter in separate packages
- Run
python3 -Vfirst, then install the matchingpython-tk@X.Y - Installing
tcl-tkand setting environment variables is normally unnecessary (python-tk brings it in) - If it fails only inside a virtual environment, rebuild the venv
- pyenv requires a rebuild. That is the one case where the environment variables matter
/usr/bin/python3works, but its Tk is 8.5 and it is not suited to daily use- Reinstalling Homebrew is a last resort
Multiple Pythons on one machine make diagnosis dramatically harder. Establishing which Python is actually running is what keeps this from turning into a long detour.
