The go-to resource for upgrading Python, Django, Flask, and your dependencies.

Django & Flask Upgrade Guide

Learn how to keep your Python web frameworks modern and fast.

Monitor lizards don't grow and then stop — they grow continuously throughout their lives, though the rate slows as they age. Unlike mammals with growth plates that fuse, reptiles maintain the ability to add new bone and tissue incrementally. This continuous growth requires regular feeding, frequent basking to regulate metabolism, and periodic skin shedding to accommodate the larger body. A monitor that tried to delay shedding for years would find itself trapped in skin that no longer fits, unable to move properly or fight off infections.

Django and Flask applications grow continuously as well — new features, changing requirements, evolving security standards. Treating framework upgrades as a massive, once-every-five-years event creates the same problem as a lizard refusing to shed: the application becomes trapped in outdated dependencies, unable to adopt new features or receive security patches. Instead, upgrading frameworks should be a continuous process, maintaining pace with the application's growth.

The Continuous Upgrade Philosophy

The most effective way to manage upgrades is to stay close to the latest stable releases, or at least maintain current point releases. When you encounter a major version upgrade, comprehensive test coverage becomes your greatest asset. We will explore a systematic approach to bridging the gap between major versions.

Preparing for the Upgrade

Before we change any code, we must understand our current state.

Resolving Deprecations

Always fix deprecation warnings on your current framework version before attempting to jump to the next one. Both Django and Flask core teams typically introduce deprecation warnings in minor versions and remove the underlying code in the subsequent major release.

Auditing Dependencies

We can audit our dependencies using pip:

$ pip list --outdated
Package    Version  Latest   Type
---------  -------  -------  -----
Django     4.2.0    5.1.0    wheel
Flask      2.3.0    3.1.0    wheel

This command will show which packages have newer versions available. Often, package maintainers release new versions specifically to support upcoming framework releases.

Django Upgrade Process

There are two major approaches to working through a Django upgrade; depending on your particular circumstances, one may be more appropriate than the other.

The first approach is a branch-based upgrade. You create a new git branch, update the dependencies, fix the tests, and eventually merge it back. This approach works well for smaller applications or teams with limited concurrent development.

The second approach is the dual-boot strategy. This involves configuring your application to run on both the old and new Django versions simultaneously using separate lock files.

The branch-based upgrade is less complex to set up. The dual-boot strategy typically makes more sense when upgrading a large application while a team continues merging new features into the main branch.

Updating Requirements

When ready to proceed, update your requirements.txt or pyproject.toml to point to the new version. It is crucial to upgrade one minor version at a time — for example, from 4.2 to 5.0, then from 5.0 to 5.1. Do not skip minor versions.

One may wonder: if we have comprehensive test coverage, why upgrade one minor version at a time?

Deprecation warnings are typically introduced in minor versions and removed in the subsequent major version. If we skip minor versions, we lose the opportunity to see and address those deprecations before they become exceptions.

Django>=5.0,<5.1

After updating the file, we can install the new version:

$ pip install --upgrade Django
Collecting Django
Installing collected packages: Django
Successfully installed Django-5.0.0

Running Migrations

Django may introduce new system migrations in major releases. After upgrading, run:

$ python manage.py makemigrations
$ python manage.py migrate

This ensures all database schema changes are applied correctly.

Testing and Remediation

Finally, we run our test suite against the new version and address any breaking changes:

$ python manage.py test

Flask Upgrade Process

Flask upgrades tend to be less structured than Django upgrades — Flask is a microframework with fewer conventions — but the same principles apply.

Updating Flask

Update your requirements.txt or pyproject.toml:

Flask>=3.0,<4.0

Then install:

$ pip install --upgrade Flask

Werkzeug Compatibility

Flask depends heavily on Werkzeug. Major Flask upgrades often coincide with Werkzeug upgrades, which can introduce breaking changes in routing, request handling, or security utilities. Always check the Werkzeug changelog when upgrading Flask.

Testing Flask Applications

Run your test suite to verify compatibility:

$ pytest

Common issues include changes to flask.json module, session handling, or deprecated import paths.

Common Upgrade Patterns

Regardless of which framework you're using, certain patterns hold true: