Install & Compatibility
Where this runs
tested against v4.3.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.777s · 66.6MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 6.3s · import 0.747s · 67MB
66MB installed
● package 66MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
ProtocolTypeRouter
✓ from channels.routing import ProtocolTypeRouter
Used in asgi.py to route different protocol types (http, websocket).
URLRouter
✓ from channels.routing import URLRouter
Used within ProtocolTypeRouter to route WebSocket paths to specific consumers.
AuthMiddlewareStack
✓ from channels.auth import AuthMiddlewareStack
Wraps WebSocket consumers to enable Django's authentication and session features.
WebsocketConsumer
✓ from channels.generic.websocket import WebsocketConsumer
Base class for synchronous WebSocket consumers.
AsyncWebsocketConsumer
✓ from channels.generic.websocket import AsyncWebsocketConsumer
Base class for asynchronous WebSocket consumers.
sync_to_async
✓ from asgiref.sync import sync_to_async
Helper to call synchronous code from asynchronous contexts (e.g., database access in async consumers).
async_to_sync
✓ from asgiref.sync import async_to_sync
Helper to call asynchronous code from synchronous contexts (less common in consumers).
get_asgi_application
✓ from django.core.asgi import get_asgi_application
The standard way to integrate Django's HTTP handling into an ASGI application (supersedes channels.http.AsgiHandler).
This quickstart demonstrates a minimal `asgi.py` configuration using `ProtocolTypeRouter` to handle both HTTP (via Django's `get_asgi_application()`) and WebSocket connections. It includes `AuthMiddlewareStack` for session and authentication support and `AllowedHostsOriginValidator` for security. The example uses an inline echo consumer for immediate testing, but typically you would define consumers in an app's `consumers.py` and route them via a `routing.py` module. To run this, you would also need `daphne` installed and configured in `INSTALLED_APPS`.
import os
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from django.urls import path
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
# myapp/consumers.py (example consumer)
# from channels.generic.websocket import AsyncWebsocketConsumer
# import json
# class ChatConsumer(AsyncWebsocketConsumer):
# async def connect(self):
# self.room_name = self.scope['url_route']['kwargs']['room_name']
# self.room_group_name = 'chat_%s' % self.room_name
# await self.channel_layer.group_add(
# self.room_group_name,
# self.channel_name
# )
# await self.accept()
#
# async def disconnect(self, close_code):
# await self.channel_layer.group_discard(
# self.room_group_name,
# self.channel_name
# )
#
# async def receive(self, text_data):
# text_data_json = json.loads(text_data)
# message = text_data_json['message']
# await self.channel_layer.group_send(
# self.room_group_name,
# {
# 'type': 'chat_message',
# 'message': message
# }
# )
#
# async def chat_message(self, event):
# message = event['message']
# await self.send(text_data=json.dumps({'message': message}))
# myproject/routing.py
# from django.urls import re_path
# from myapp import consumers
#
# websocket_urlpatterns = [
# re_path(r'ws/chat/(?P<room_name>\w+)/$', consumers.ChatConsumer.as_asgi()),
# ]
# Root ASGI application in myproject/asgi.py
application = ProtocolTypeRouter({
"http": django_asgi_app,
"websocket": AllowedHostsOriginValidator(
AuthMiddlewareStack(
URLRouter(
# myproject.routing.websocket_urlpatterns # Uncomment and define your routing
[
path("ws/echo/", (lambda scope: type('EchoConsumer', (object,), {'as_asgi': lambda: lambda scope, receive, send: (async def _(): await scope['accept'](), await scope['send']({'type': 'websocket.accept'}), async for msg in scope['receive'](): await scope['send']({'type': 'websocket.send', 'text': msg['text']})})())())(0).as_asgi())
]
)
)
),
})
Debug
Known issues
breakingChannels 1.x to 2.x was a complete rewrite, introducing Python's asyncio framework and running async-native. It is not backwards-compatible, requiring significant code changes and dropping Python 2.7/3.4 support. The `channel_session` concept was removed, and applications now run inside their protocol servers.fixRefer to the Channels 2.x migration guide for porting applications. Expect to rewrite consumer and middleware logic to use async/await and new API patterns. Update Python to 3.5+.
affects: <2.0.0
breakingChannels 3.x introduced ASGI v3 compliance, aligning with Django's native ASGI support (Django 3.0+). Consumers now require an `.as_asgi()` class method when used in routing. Middleware signatures changed, and `channels.http.AsgiHandler` was deprecated in favor of Django's `get_asgi_application()`.fixEnsure consumers are called with `.as_asgi()` in your routing. Update custom middleware to the new ASGI v3 signature. Replace `AsgiHandler` with `django.core.asgi.get_asgi_application` for HTTP handling.
affects: <3.0.0
breakingChannels 4.x made Daphne an optional dependency. It also removed deprecated static files handling and the `AsgiHandler`. The minimum supported Django version is 3.2, and Python 3.7. (As of 4.3.2, Python >=3.9 and Django 4.2+ are supported).fixExplicitly install `daphne` if you intend to use it. Update your `asgi.py` to use `django.core.asgi.get_asgi_application()` for HTTP. Ensure your Python and Django versions meet the new minimum requirements.
affects: <4.0.0
gotchaMixing synchronous Django ORM operations with asynchronous Channels consumers can lead to blocking issues if not handled correctly. Django's database access is synchronous.fixUse `asgiref.sync.sync_to_async` to wrap synchronous database calls or any blocking synchronous code when called from an asynchronous consumer (e.g., `await sync_to_async(MyModel.objects.get)(id=some_id)`).
affects: All versions
gotchaFor distributed applications, real-time communication between multiple consumer instances, or persisting messages across processes (e.g., chat rooms), a channel layer backend (like `channels_redis`) is crucial. The default `InMemoryChannelLayer` is only suitable for single-process development and will not work across multiple servers or even multiple worker processes.fixConfigure a production-ready channel layer like `channels_redis` in your `settings.py` (e.g., `CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer', 'CONFIG': {'hosts': [('localhost', 6379)]}}}`). Ensure Redis is running and accessible. affects: All versions
gotchaIt's critical to initialize Django's ASGI application early in your `asgi.py` file (`django_asgi_app = get_asgi_application()`) to ensure the Django AppRegistry is fully populated before any ORM models or app-specific code is imported within your Channels routing or consumers.fixPlace `os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')` and `django_asgi_app = get_asgi_application()` at the top of your `asgi.py` before any imports from Django apps or Channels routing that might touch Django models. affects: All versions (especially with Django 3.0+)
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'channels'
This error indicates that the 'channels' package is not installed or not accessible in the current Python environment, or there's a typo in the import statement.
fixEnsure the channels package is installed correctly in your virtual environment: `pip install channels`
ValueError: No route found for path '%r.'
This error occurs when Channels cannot find a matching route in your `asgi.py`'s `URLRouter` for the incoming WebSocket or HTTP connection path. It often points to a mismatch between the client's requested URL and the patterns defined in `routing.py`.
fixVerify that your `routing.py` file correctly defines URL patterns (using `path()` or `re_path()`) that match the WebSocket connection URL initiated by your client, including any leading/trailing slashes or parameters. For example:
```python
# your_project/routing.py
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
]
# your_project/asgi.py (ensure URLRouter is used)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
import your_project.routing
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(
URLRouter(your_project.routing.websocket_urlpatterns)
),
})
``` ValueError: No application configured for scope type 'websocket'
This error typically means your `asgi.py` is configured to handle HTTP requests (via `get_asgi_application()`) but does not include a `websocket` entry in the `ProtocolTypeRouter` to direct WebSocket connections to a consumer.
fixEnsure your `asgi.py` file uses `ProtocolTypeRouter` and explicitly includes a `'websocket'` key pointing to your WebSocket routing configuration:
```python
# your_project/asgi.py
import os
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from django.urls import path # Import path for direct routing, or import your routing module
from myapp import consumers # Example: import your app's consumers
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': URLRouter([
path('ws/some_path/', consumers.MyConsumer.as_asgi()),
# ... other websocket paths
]),
})
``` ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured.
This happens when Django's settings or `AppRegistry` are not fully initialized before Channels components (like consumers or models) are imported or accessed. This often occurs due to incorrect import order in `asgi.py` or attempts to access Django models too early.
fixIn your `asgi.py`, ensure that `django.setup()` (if used outside `get_asgi_application()`) or `get_asgi_application()` is called early enough to initialize Django's settings and AppRegistry before any imports that rely on Django models or settings. Placing `get_asgi_application()` and related imports at the top of your `asgi.py` after `DJANGO_SETTINGS_MODULE` is set typically resolves this.
```python
# your_project/asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()
# Now import other Channels components (like ProtocolTypeRouter, URLRouter, consumers)
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
# import your app's routing module or consumers here
import myapp.routing
application = ProtocolTypeRouter({
'http': django_asgi_app,
'websocket': AuthMiddlewareStack(
URLRouter(myapp.routing.websocket_urlpatterns)
),
})
``` Upgrade
Version history
4.3.2latest on PyPI · released Nov 20, 2025
Audit
Dependencies
DjangorequiredCore framework extension.
asgirefrequiredBase ASGI library, core dependency for async utilities.
daphneoptionalHTTP and WebSocket termination server (recommended for production deployment).
channels-redisoptionalRedis-backed channel layer for inter-process communication (recommended for production/distributed setups).