Skip to content

Python·8 min read

Python 3.10 reached end of life on 1 October: a dependency-first upgrade plan for production services

Python 3.10 stopped getting fixes with 3.10.22 on 1 October 2026, and AWS deprecated the python3.10 Lambda runtime on 31 October. Bump dependencies first while you are still on 3.10, target 3.13 or 3.14, and move one service at a time behind a CI matrix.

Anatoli NavahrodskiFounder & CEO, GlanitPublished 1 November 2026
Python 3.10 reached end of life on 1 October: a dependency-first upgrade plan for production services

What exactly stopped on 1 October 2026?

Upstream maintenance stopped. Python 3.10.22, released on 1 October 2026, was the last release of the series. PEP 619 is now marked Final and says the 3.10 codebase "is now frozen and no further updates will be provided nor issues of any kind will be accepted on the bug tracker". Your services keep running exactly as they did on 30 September. What ends is the supply of fixes: the next security patch to the standard library lands in 3.11 and later, never in 3.10. Packagers follow on their own clocks. The official Docker python image removed 3.10 from its build definitions in a pull request merged on 6 October, and Heroku stops building 3.10 apps on 6 January 2027.

The rest of the support table is short. Per the Python devguide, 3.11 gets security fixes until October 2027, 3.12 until October 2028, 3.13 until October 2029 and 3.14 until October 2030. Python 3.15 shipped on 9 October 2026.

Five-year windows, one release a year. Whatever you pick, you will be back here.

Where is 3.10 still running in your estate?

Wherever someone once typed "3.10". The version is almost never pinned in one place. It sits in Dockerfile FROM lines, CI images, .python-version, requires-python, tox and ruff targets, SAM or Serverless templates, on a cron VM built from Ubuntu 22.04 (whose default python3 package depends on python3.10), and in a notebook kernel nobody remembers creating. Grep the repositories first, then ask the cloud.

# every place a 3.10 pin can hide in a repo
rg -n --hidden -g '!.git' \
  -e 'python:3\.10' -e 'python3\.10' -e 'python-version.*3\.10' \
  -e 'requires-python.*3\.10' -e 'py310' .

# zip-packaged Lambda functions, one region and account per call
aws lambda list-functions --function-version ALL --region eu-central-1 \
  --output text --query "Functions[?Runtime=='python3.10'].FunctionArn"

That AWS query is the one from Amazon's own guide, and it has two gaps. It covers one region per call. And container-image functions carry no runtime identifier, so they never match; AWS also sends no deprecation notices for them and states that rebuilding the image is your job. For those, the Dockerfile grep above is the inventory.

3.12, 3.13 or 3.14: which one do we pick?

We pick 3.14 when the lockfile resolves for it, 3.13 when one compiled dependency holds it back, and 3.12 only under a hard pin we cannot lift this quarter. 3.11 is off the list. It buys twelve months of upstream support, NumPy dropped it in 2.5.0 on 21 June 2026, Heroku has already deprecated it, and the python3.11 Lambda runtime runs on Amazon Linux 2. Moving twice costs more than moving once.

On Lambda the choice is flatter than it looks. AWS lists python3.13 and python3.14 with the same deprecation date, 30 June 2029, so the extra upstream year of 3.14 buys nothing there yet. In containers it does. The usual objection to the newest version is wheel lag for compiled packages, and Ruzora's October guide still names numpy, pandas and psycopg as candidates. A year after release that objection has weakened (NumPy 2.5 and Django 6.0 both list 3.14), but check your own lock rather than anyone's blog, including this one:

uv pip compile requirements.in --python-version 3.14 \
  --python-platform linux -o /tmp/req-py314.txt

If that resolves, 3.14 is on the table. If it fails on one package, read the error before you settle for 3.13; sometimes the fix is a newer minor of that package.

Four targets, four deadlines

The table puts the upstream date, the Lambda date and the first thing that breaks side by side. The column that decides most migrations is the last one.

Upgrade targets compared

Upgrade targets as of 1 November 2026.
TargetUpstream security fixes untilAWS Lambda deprecationWhat bites on arrival
3.11October 202730 Jun 2027 (Amazon Linux 2)NumPy 2.5+ and Django 6.x will not install
3.12October 202831 Oct 2028 (AL2023)distutils, imp, asyncore, asynchat removed; venv no longer pre-installs setuptools
3.13October 202930 Jun 2029 (AL2023)The 3.12 removals plus 19 PEP 594 modules (cgi, crypt, imghdr, telnetlib, pipes…) and lib2to3
3.14October 203030 Jun 2029 (AL2023)Everything above; read 3.14's own What's New before committing
Upgrade targets as of 1 November 2026. — Upstream dates for 3.11 to 3.14 are scheduled, not final. Sources: Python devguide, AWS Lambda runtimes page, What's New in 3.12 and 3.13.

Why do dependencies break the upgrade before your code does?

Because your service imports a few hundred packages and each has its own requires-python. Bump them first, on 3.10, to the newest versions that support both 3.10 and your target. Then the interpreter switch only surfaces interpreter problems. Change both at once and every red test could come from either side, and you spend days bisecting.

Django shows the pattern. Django 5.2 LTS runs on 3.10 through 3.14 and gets security fixes until 30 April 2028; Django 6.0, released 3 December 2025, requires 3.12, and its release notes say the 5.2 series "is the last to support Python 3.10 and 3.11". So the path is 5.2 on 3.10, then the interpreter, then 6.x as its own change. pandas works the same way: 3.0 (21 January 2026) needs Python 3.11 or newer, and the pandas team asks you to reach 2.3 and clear the warnings first.

The code-side breakage is a known list. Python 3.12 removed distutils (PEP 632), imp, asyncore and asynchat, and new virtualenvs stopped getting setuptools pre-installed, so a build script that quietly relied on pkg_resources dies with ModuleNotFoundError: No module named 'pkg_resources'. Invalid escape sequences like "\d" became a SyntaxWarning, which is a CI failure if you run tests with warnings as errors. Python 3.13 then removed the 19 PEP 594 "dead batteries", plus lib2to3. Most have PyPI stand-ins (standard-imghdr, legacycrypt, standard-telnetlib). We treat those as a bridge. If one is still in requirements.txt a year later, someone should own replacing it.

One uv detail matters when you edit requires-python. A universal lock must satisfy every dependency across the whole declared range, so >=3.10 keeps you on whatever still installs on 3.10. Raise the floor only after the switch.

The Lambda deadline is softer than it looks

AWS deprecated python3.10 on 31 October 2026, yet nothing stops this month. Creating functions is blocked from 29 July 2027, updating them from 31 August 2027, and invocations continue indefinitely. What ended on 31 October is AWS's side of the deal: no more security patches to the runtime, no technical support, and the console no longer creates or updates python3.10 functions. CLI, SAM and CloudFormation still do.

That gap is the trap. Nine months of "it still deploys" is how functions end up on a frozen runtime. Two details from the AWS docs shape the plan. After the update block you cannot move a function back to the deprecated runtime, so rollback has to be a published version behind an alias, prepared before the switch. And python3.10 runs on Amazon Linux 2 while 3.12 and later run on AL2023, so rebuild any layer with native code against the new runtime instead of reusing the old zip.

One service at a time, behind a CI matrix

Run the suite on 3.10 and the target in parallel until the target is green, swap the base image, soak in staging, then move services one by one. AWS's guide suggests ranking functions by invocation count. We use that ranking for the deadline and invert it for the first move: the first service should be low-traffic and internal, so the surprises land somewhere cheap.

# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-24.04
    strategy:
      fail-fast: false
      matrix:
        python: ["3.10", "3.13"]
        include:
          - python: "3.14"
            experimental: true
    continue-on-error: ${{ matrix.experimental || false }}
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-python@v7
        with:
          python-version: ${{ matrix.python }}
      - run: pip install -r requirements.txt && pytest -W error::SyntaxWarning

After green, build on the new base (python:3.13-slim, or the AWS Lambda base image for 3.13), deploy to staging and watch error rate and p95 latency for several days before promotion. Ruzora's worked example puts a typical Django or FastAPI service at one to two engineer-weeks and walks through a 12-engineer-day case. That is a vendor estimate for one illustrative service. The factor that moves it most is how stale the dependency tree is on day one.

When is paying for extended support legitimate?

When it buys time for a move that already has a date. Ubuntu 22.04 fleets are the common case: Canonical keeps patching the distro's python3.10 under standard support until 1 June 2027 and under Ubuntu Pro ESM until April 2032. That covers the interpreter Canonical ships. It does not cover what pip installed into your virtualenv, and those maintainers leave 3.10 one release at a time. Platforms are drawing the same line. Retool ended 3.10 support in Workflows on 31 October 2026 and does not migrate workflows automatically.

On compliance, auditors and customer security questionnaires ask about unsupported software, and an interpreter with no upstream fixes is an awkward answer. If you sell software into the EU, the Cyber Resilience Act reporting duties make unpatched components a vendor problem. We are engineers, so read that as a reason to check with counsel. The same goes for anything an AI agent can reach: an MCP server pinned to 3.10 is on the inventory too.

What we would do next time

Start at the deprecation notice. Heroku deprecated 3.10 on 21 November 2025, and AWS emails account owners at least 180 days before a runtime deprecation, so the warning was there for most of a year. Next time we would put the inventory grep into CI the week a version's successor ships, and add the newest Python as an allowed-failure leg in the matrix that same week. Python 3.15 came out on 9 October 2026, and AWS lists a python3.15 Lambda runtime in public preview with general availability targeted for November 2026, so that leg can go in now. When 3.11 reaches its end in October 2027, the move should be a config change. The method is the one we use for legacy PHP estates: inventory, dependencies, then the runtime, in that order.

If you want a second pair of eyes, we run a one-week Python runtime and dependency inventory and hand back a staged upgrade plan per service. See our web development services or get in touch.

Frequently asked questions