Skip to content

Implement fully async-capable support for django.middleware.common.CommonMiddleware #102

@Arfey

Description

@Arfey

Code of Conduct

  • I agree to follow Django's Code of Conduct

Feature Description

Django currently ships all its built-in middleware as synchronous MiddlewareMixin, which forces the entire request stack through sync_to_async, preventing users from achieving a fully asynchronous request flow. To enable a true async pathway, Django needs async-capable versions of these middlewares without breaking existing custom middleware that subclasses them.

Problem

From the Django documentation:

You will only get the benefits of a fully asynchronous request stack if you have no synchronous middleware loaded into your site.

Currently, all of Django's internal middleware uses MiddlewareMixin and relies on sync_to_async under the hood. This makes it difficult for end users to have a fully async request flow, because they would need to copy and adapt all internal logic for each middleware, and maintain it across Django releases.

Some internal middleware only performs CPU-bound operations and does not require async/AIO logic, so it could safely be used in both sync and async contexts without sync_to_async.

Options to solve this:

  1. Implement __acall__ without sync_to_async
    Not recommended. Can lead to subtle bugs if users subclass and customize the middleware:
class CustomCommonMiddleware(CommonMiddleware):
    def process_response(self, request, response):
        # custom logic
        return super().process_response(request, response)

In an async context, this custom logic would be ignored or behave unexpectedly.

  1. Rewrite middlewares using sync_and_async_middleware decorator

Safe and straightforward. Breaking change: would break all existing custom middleware that inherits from the internal middleware.

  1. Implement separate async middleware (AsyncCommonMiddleware)

Compromise solution. Safe for users: they can explicitly replace CommonMiddleware with AsyncCommonMiddleware in async setups.

I'm going to start by implementing an async version of CommonMiddleware as a test case for this approach. Once we validate it, the plan is to extend the same pattern to:

  • django.contrib.auth.middleware.AuthenticationMiddleware
  • django.middleware.locale.LocaleMiddleware
  • django.middleware.security.SecurityMiddleware

If you have any thoughts or concerns about this approach, especially regarding edge cases or backward compatibility, please share them.

Request or proposal

proposal

Additional Details

No response

Implementation Suggestions

MR with example https://github.com/Arfey/django/pull/4/files

Metadata

Metadata

Assignees

No one assigned

    Labels

    AsyncDjango CoreThis idea is suitable for inclusion in Django itself.Middleware

    Type

    No type

    Projects

    Status

    Idea

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions