django / django/new-features

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

Open
#102 8 comments 9 reactions 0 assignees View on GitHub
Async Django Core Middleware
Dominant language
No language data
Stars
188
Forks
7
PR merge metrics
No merged PRs in 30d

Description

### Code of Conduct

- [x] 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:

```python
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.

2. 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.

3. 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](https://github.com/Arfey/django/pull/4/files)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.