That Python 3.8 vs 3.11 Problem Finally Pushed Me to Use pyenv

A few weeks ago, I opened an old Python project to fix what I thought would be a quick issue.
The code looked fine. The logic made sense. But the script refused to run.
After a bit of digging, the problem became obvious: the project was written for Python 3.8, while my system was happily running Python 3.11.
If you've worked with Python long enough, you've probably been here too — juggling different projects, each expecting a different Python version, and slowly realizing that "just using system Python" doesn't scale.
That's exactly the headache pyenv solves.
If you're dealing with Python version conflicts today, this article is meant to be followed — not just read.
In this guide, I'll walk you through how I actually fixed the problem, verified it worked, and ended up with a setup I now trust.
🔧 How I Finally Fixed the Python 3.8 vs 3.11 Mess
At first, I tried the usual shortcuts.
I upgraded a few dependencies. Then I downgraded others. I even briefly considered installing another Python version directly on my system — before remembering how badly that had gone in the past.
The real issue wasn't the project.
It was my setup.
I needed a way to:
- keep my system Python untouched,
- run Python 3.8 for this project,
- and still use newer Python versions elsewhere.
So before changing anything, I checked what my system was actually using:
python --version
# Python 3.11.4
And where it was coming from:
which python
# /usr/bin/python
That confirmed it — I was running system Python, which I really didn't want to mess with.
🔹 Installing Python 3.8 Without Breaking Anything
Instead of uninstalling or downgrading anything globally, I installed Python 3.8 alongside my existing version using pyenv.
pyenv install 3.8.16
After a few minutes of compilation, I verified the installation:
pyenv versions
# system
# * 3.11.4
# 3.8.16
Both versions now existed side by side — safely.
🔹 Locking Python 3.8 to Just This Project
Inside the project directory, I ran:
pyenv local 3.8.16
This automatically created a .python-version file.
To confirm:
python --version
# Python 3.8.16
Then I opened a new terminal, navigated back into the same directory, and checked again:
python --version
# Python 3.8.16
No activation steps. No environment variables. It just worked.
🔹 Verifying Nothing Else Broke
This part mattered to me the most.
Outside the project directory:
cd ~
python --version
# Python 3.11.4
System Python was untouched. That was the moment I stopped worrying about breaking my machine.
🔹 Double-Checking the Active Binary (Optional but Reassuring)
If you ever want to be absolutely sure which Python executable is running:
pyenv which python
# ~/.pyenv/versions/3.8.16/bin/python
No guesswork involved.
✅ Why This Setup Finally Felt Right
What I liked about this setup wasn't just that it solved this problem.
It gave me:
- confidence that my system Python was safe,
- clarity about which Python version each project was using,
- and a setup I could easily explain (or share) with teammates.
What really stood out was how boring it all became — in the best possible way.
- No
sudo. - No system-level changes.
- No fragile shell aliases.
Just a small .python-version file that clearly said:
"This project uses Python 3.8."
Once that was in place, I could focus on the code again — not the environment.
That's when I realized pyenv wasn't just a convenience tool. It was a sanity tool.
🧪 Adding Isolation: pyenv + virtualenv (The Missing Piece)
At this point, Python 3.8 was working correctly — but I still wanted one more layer of safety.
Even with the right Python version, I didn't want dependencies leaking across projects.
Installing pyenv-virtualenv
brew install pyenv-virtualenv
Restart the terminal (important), then verify:
pyenv virtualenvs
# (no output yet — expected)
Creating a Project-Specific Virtual Environment
pyenv virtualenv 3.8.16 myproject-3.8
pyenv local myproject-3.8
This updated the same .python-version file — now pointing to the virtual environment.
Verification:
python --version
# Python 3.8.16
pyenv version
# myproject-3.8 (set by /path/to/project/.python-version)
Installing Dependencies Safely
pip install -r requirements.txt
pip list
Everything installed cleanly — and only inside this environment.
Verifying Isolation Actually Works
Outside the project:
cd ~
pip list
Inside the project again:
cd myproject
pip list
The difference was clear. That's when I knew the setup was doing exactly what I wanted.
🔹 Optional Tip for Teams
If you commit the .python-version file to your repo, teammates using pyenv will automatically get the correct Python and virtualenv when they enter the project directory.
It's a small thing that quietly saves everyone time.
🐍 What Is pyenv (Briefly)?
pyenv is a tool for managing multiple Python versions on the same machine.
It works by:
- installing Python versions side by side,
- letting you switch versions globally or per project,
- and keeping system Python untouched.
❓ Why You Might Need It
pyenv is especially useful when:
- an old project needs Python 3.6 or 3.8,
- you want to test code across multiple Python versions,
- your team uses different setups,
- or you simply want to avoid touching system Python.
🙋 Frequently Asked Questions
Does pyenv create temporary environments?
No. It installs persistent Python versions under ~/.pyenv/versions/.
What's the difference between pyenv and virtualenv?
pyenvmanages Python versionsvirtualenvmanages dependencies
Use both together for full isolation.
Does pyenv affect system Python?
No. It works at the shell level only. Your OS continues using its default Python.
Can I use pyenv with poetry, pipenv, or pipx?
Yes — they integrate cleanly once pyenv is set up.
📌 Final Thoughts
pyenv is one of those tools you don't think about once it's set up — and that's precisely why it's so valuable.
Once you start using it:
- you stop worrying about breaking system Python,
- switching projects becomes effortless,
- and "works on my machine" stops being an excuse.
For me, pyenv turned Python version management from a recurring frustration into something boring and predictable — the good kind of boring.
If this article saved you some setup time (or prevented a future Python meltdown), feel free to clap, share it, or bookmark it — your future self might thank you.



