[MORSALIN]
← All guides
GuideUpdated September 26, 20265 min read

Python 3.10 end of life (31 October 2026): what it means and how to upgrade

Python 3.10 stops getting security fixes in October 2026. Move to Python 3.12 or 3.13; watch for removed modules, distutils and old packages.

Deadline: October 31, 2026 · 36 days leftCheck your stack →Fixed-price upgrade from $390 →

If your application, API, worker or data pipeline runs on Python 3.10, security support ends in October 2026. Python's developer guide lists the end of life as 2026-10, and endoflife.date gives 31 October 2026. "End of life" means the Python team stops releasing new 3.10 versions, so security holes found after that date are not fixed in official Python 3.10 releases. This affects Django, Flask and FastAPI apps, Celery workers, scripts and scheduled jobs alike.

What changes on the date (and what doesn't)

Python 3.10 has had source-only security releases since its last bugfix release in April 2023 (PEP 619). In October 2026 even those stop.

What does not change:

  • Your servers and containers keep running. Nothing is switched off.
  • Some distributions and vendors keep patching their own Python builds. Ubuntu 22.04 LTS ships Python 3.10 as its system Python, and Canonical backports security fixes to it for the life of that release (longer with Ubuntu Pro/ESM). Red Hat and other enterprise distributions do the same for the versions they ship, and vendors such as HeroDevs sell extended support. These options exist; whether they cover you depends on where your Python comes from.

What does change:

  • The official python:3.10 Docker images and python.org builds stop getting updates.
  • Libraries drop Python 3.10 support over time. New releases of your dependencies may require 3.11 or 3.12, which leaves you on old, unpatched versions of those libraries too.
  • Security scanners and compliance reviews flag the unsupported runtime.

Which versions to move to

Version Security support until Notes
Python 3.10 Oct 2026 (31 Oct per endoflife.date) Ends this year
Python 3.11 Oct 2027 Buys one year
Python 3.12 Oct 2028 Good default target
Python 3.13 Oct 2029 Good target if your packages support it
Python 3.14 Oct 2030 Newest; check package support first

Source: Python developer guide, status of Python versions, cross-checked with endoflife.date/python.

I usually recommend Python 3.12 or 3.13. Most maintained packages ship wheels for both, and either gives you two to three years before the next move. Python 3.11 is the smallest jump, but you'd be doing this again in 2027.

How to check what you run

Check each place Python runs: servers, containers, CI, serverless functions and developer machines. They often differ.

# The interpreter on the server or in the container
python --version
python3 --version

# Inside a virtualenv, confirm which interpreter it was built from
.venv/bin/python --version

# What your project declares
grep -n "requires-python" pyproject.toml     # e.g. requires-python = ">=3.10"
grep -n "python_requires" setup.cfg setup.py 2>/dev/null
cat .python-version runtime.txt 2>/dev/null

# Docker base image
grep -i '^FROM' Dockerfile                    # e.g. FROM python:3.10-slim

# CI images and matrices
grep -rn "python-version\|python:3" .github/ .gitlab-ci.yml 2>/dev/null

For a quick check without running anything, paste your pyproject.toml or Dockerfile into the free stack health check. It runs in your browser and shows which runtimes and frameworks are past or near end of life.

Upgrade checklist

  1. Inventory. List every app, worker, cron job, Lambda or Cloud Function, and CI pipeline that runs Python, with its version and where the interpreter comes from (system package, Docker image, pyenv, uv).
  2. Tests first. Get the test suite green on 3.10. If coverage is thin, add tests for the flows that matter most: sign-in, payments, imports, the main API endpoints.
  3. Show warnings. Run the tests with python -W default -m pytest (or -W error::DeprecationWarning to make them fail). Warnings on 3.10 point at code that breaks later.
  4. Fix removals and deprecations for your target version:
    • Python 3.11 (What's New): asyncio.coroutine is removed; use async def. The binhex module is removed.
    • Python 3.12 (What's New): distutils, imp, asynchat, asyncore and smtpd are removed; unittest aliases such as assertEquals are removed; configparser.SafeConfigParser is removed; venv no longer pre-installs setuptools; invalid escape sequences like "\d" now raise SyntaxWarning; datetime.utcnow() is deprecated in favor of datetime.now(datetime.UTC).
    • Python 3.13 (What's New): 19 old modules are removed, including cgi, cgitb, crypt, imghdr, pipes, telnetlib, nntplib and audioop; lib2to3 and 2to3 are removed; locals() in functions now returns an independent snapshot (PEP 667).
  5. Update dependencies. Upgrade your pins (requirements.txt, poetry.lock, uv.lock) to versions that support the target Python. Watch packages with compiled parts (NumPy, pandas, psycopg2, lxml, cryptography): old versions have no wheels for new Python versions and try to build from source, which often fails in slim images.
  6. Framework notes. Check the Django FAQ table: Django 5.2 LTS supports Python 3.10 to 3.14, while Django 6.0 and 6.1 need Python 3.12 or newer. Current FastAPI releases require Python 3.10 or newer (PyPI), so FastAPI itself runs fine on 3.12 and 3.13; upgrade FastAPI and Pydantic together if you're on old versions.
  7. Update requires-python, the Dockerfile and CI. Run the CI matrix on 3.10 and the target version until the switch, then drop 3.10.
  8. Staging. Deploy to staging with the same image and settings as production. Test background workers, scheduled jobs, file handling and outbound integrations, not just the web pages.
  9. Deploy with a rollback. Ship a new image or a new server, keep the old one ready, and watch logs and error tracking for a few days.

Common breakages

  • ModuleNotFoundError: No module named 'distutils' on 3.12, usually from an old package's setup.py or code that used distutils.util.strtobool. Upgrade the package or replace the call.
  • ModuleNotFoundError: No module named 'imp' from old plugins or vendored code. Use importlib.
  • ModuleNotFoundError: No module named 'cgi' on 3.13, often from old web or email-parsing code. The same happens with imghdr, pipes and telnetlib.
  • AttributeError: ... has no attribute 'assertEquals' in test suites on 3.12. Rename to assertEqual and the other modern names.
  • Failed installs because a pinned version of a compiled package has no wheel for the new Python and the build tools aren't in the image.
  • SyntaxWarning: invalid escape sequence flooding logs from regex strings. Use raw strings (r"\d+").
  • Timezone bugs when replacing utcnow() without care: datetime.now(datetime.UTC) returns an aware datetime, and comparing it with naive values raises TypeError.

Cost and timeline

The honest answer is that it depends on test coverage and on how far behind your dependencies are. A FastAPI or Django app with tests and maintained packages can move from 3.10 to 3.12 in a few days. An app with no tests, old pins, and code that uses removed modules takes longer, because each of those needs a fix and a check.

Start before October so you have time for staging and for waiting on a library release if you need one.

I do this as a fixed-price service: the End-of-Life Runtime Upgrade starts from $390 for one runtime. If you're not sure how much work is hidden in the code, a codebase assessment gives you a written answer before you commit.

If Python 3.10 is in your stack, send me your versions and I'll tell you what the move involves.

Questions

When does Python 3.10 reach end of life?

In October 2026. Python's developer guide lists end of life as 2026-10, and endoflife.date gives 31 October 2026. After that, the Python team releases no more 3.10 versions, including security fixes.

Will my Python 3.10 app stop working after October 2026?

No. The interpreter keeps running. The risk is that security holes found later are not fixed in official Python 3.10 releases, and new versions of your libraries stop supporting 3.10.

Which Python version should I upgrade to?

Python 3.12 or 3.13 for most production apps. Python 3.12 is supported until October 2028 and 3.13 until October 2029. Python 3.11 only buys one year.

Does Django still support Python 3.10?

Django 5.2 LTS supports Python 3.10 to 3.14. Django 6.0 and 6.1 require Python 3.12 or newer, so upgrading Python is also what unlocks newer Django.

What breaks when moving from Python 3.10 to 3.12 or 3.13?

Most often: code or packages that import distutils, imp, asyncore or smtpd (removed in 3.12), the old stdlib modules such as cgi, telnetlib and imghdr (removed in 3.13), unittest aliases like assertEquals, and pinned packages with no wheels for the new version.

How long does a Python 3.10 upgrade take?

It depends on test coverage and how many dependencies are pinned to old versions. A tested app with maintained packages can move in days; an untested one with old pins can take a few weeks.

Written by MD Morsalin, contract software engineer. Published September 26, 2026.

Want it done for you?