What you don't know about middleware ordering could harm your website
Tags: django, codequality, webdev
Published: 2020-11-06 10:59:44

Middleware order is important hence docs for third party libraries advise _this should come before x_ or _after y._ Some middleware read headers that others set. Some set headers that affect caching. Some perform some [action on the rendered response content](https://docs.djangoproject.com/en/3.1/ref/middleware/#module-django.middleware.gzip) such as gzip.

Over a long-lived codebase it’s easy for middlware to fall out of order. During my time reviewing pull requests I give this feedback:

![code review by [Django Doctor](https://django.doctor)](https://dev-to-uploads.s3.amazonaws.com/i/3rndt0p82zdw46a0x2as.png)

Below is the order the built-in Django middlware should conform to.

### Near the start

`CommonMiddleware` As the name implies, this performs common operations we expect Django to do such as redirecting according to `APPEND_SLASH` and `PREPEND_WWW` setting. If Django is redirecting based on the URL, we want that
to happen as soon as possible, hence this middlware comes at the start. The middleware also sets content-length, which other middlwares may rely on.

`LocaleMiddleware` This handles internationalization of content. It customizes content for each user. We would not want any part of our website to miss that language-specific and user-specific customization and have the header in English the footer in German. Nien! Hence this comes early.

`SecurityMiddleware` Another well named middleware that hardens security. We would not want security to be handled near the end of the request.

### Near the end

There are two built in fallback middlwares that perform some operation if _all else fails_:

`RedirectFallbackMiddleware` This middleware handles 404s by redirecting somewhere according to redirect records set in Django admin. We would not want this to happen at the start otherwise database records would take precedence over code in urls.py, and also the database lookup would slow down the response that do not need a fallback.

`FlatpageFallbackMiddleware` Very similar to `RedirectFallbackMiddleware` but it serves flat pages instead of redirecting the user somewhere.

### Relative to each other

And then the spider web begins:

`UpdateCacheMiddleware` before `SessionMiddleware`
`UpdateCacheMiddleware` before `GZipMiddleware`
`UpdateCacheMiddleware` before `LocaleMiddleware`
`SessionMiddleware` before `LocaleMiddleware`
`GZipMiddleware` before `ConditionalGetMiddleware`
`SessionMiddleware` before `AuthenticationMiddleware`
`SessionMiddleware` before `MessageMiddleware`
`CsrfViewMiddleware` before `RemoteUserMiddleware`
`FetchFromCacheMiddleware` before `SessionMiddleware`
`FetchFromCacheMiddleware` before `GZipMiddleware`
`FetchFromCacheMiddleware` before `LocaleMiddleware`

### Does your codebase order middleware correctly?

It’s easy to miss something. I can check that for you at [django.doctor](https://django.doctor), or can [review your GitHub PRs](https://github.com/marketplace/django-doctor/):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/d10epulva9d373jgldhu.png)

Or try out [Django refactor challenges](https://django.doctor/challenge).