Skip to main content

Lightweight Django Channels layer backed by SQLite database

Project description

channels-lite

PyPI - Version PyPI - Python Version PyPI - Versions from Framework Classifiers MIT License Ruff

Django Channels layer backed by SQLite database.

channels-lite provides Django Channels channel layers that use SQLite as a backing store, eliminating the need for Redis infrastructure. Perfect for small to medium Django applications, development environments, or deployments where simplicity is valued.

There are two available implementations:

  • SQLiteChannelLayer is the Django ORM-based layer, easy to set up with no extra dependencies.
  • AIOSQLiteChannelLayer uses aiosqlite with connection pooling for better performance through direct async SQLite access.

Both layers support the full Channels layer specification including groups, flush, and capacity enforcement.

Installation

Basic Installation (Django ORM Layer)

pip install channels-lite

This installs the Django ORM-based channel layer.

High-Performance Installation (AIOSQLite Layer)

pip install channels-lite[aio]

This installs the aiosqlite-based layer with aiosqlite, aiosqlitepool, and msgspec for better performance.

Usage

Set up the channel layer in your Django settings file like so:

Django ORM Layer

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_lite.layers.core.SQLiteChannelLayer",
        "CONFIG": {
            "database": "default",
        },
    },
}

AIOSQLite Layer (High Performance)

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_lite.layers.aio.AIOSQLiteChannelLayer",
        "CONFIG": {
            "database": "default",
        },
    },
}

Configuration Options

Common Options (Both Layers)

database

Required. The Django database alias to use for channel storage. Must be a SQLite database.

"CONFIG": {
    "database": "default",  # or "channels" for separate database
}

If using a separate database for channels (recommended), configure it in DATABASES:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
    },
    "channels": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "channels.sqlite3",
        "OPTIONS": {
            "init_command": (
                "PRAGMA journal_mode=WAL; "
                "PRAGMA synchronous=NORMAL; "
                "PRAGMA busy_timeout=5000;"
            ),
        },
    },
}

Don't forget to add channels_lite to INSTALLED_APPS and run migrations:

INSTALLED_APPS = [
    # ...
    "channels_lite",
]
python manage.py migrate

expiry

Message expiry in seconds. Defaults to 60. Messages that remain undelivered after this time are automatically cleaned up.

"CONFIG": {
    "database": "default",
    "expiry": 60,
}

You generally shouldn't need to change this, but you may want to turn it down if you have peaky traffic you wish to drop, or up if you have peaky traffic you want to backlog until you get to it.

group_expiry

Group membership expiry in seconds. Defaults to 86400 (24 hours). Channels will be removed from groups after this amount of time; it's recommended you reduce it for a healthier system that encourages disconnections.

"CONFIG": {
    "database": "default",
    "group_expiry": 86400,
}

This value should not be lower than the relevant timeouts in the interface server (e.g. the --websocket-timeout to daphne).

capacity

Default channel capacity. Defaults to 100. Once a channel is at capacity, it will refuse more messages by raising ChannelFull.

"CONFIG": {
    "database": "default",
    "capacity": 100,
}

How this affects different parts of the system varies; a HTTP server will refuse connections, for example, while Django sending a response will raise an exception.

enforce_capacity

Whether to enforce capacity limits. Defaults to True. When False, allows unlimited message accumulation in the database (capacity checks are skipped).

"CONFIG": {
    "database": "default",
    "capacity": 100,
    "enforce_capacity": True,  # Set to False to disable capacity checks
}

Disabling capacity enforcement may be useful for deployments where database growth is not a concern and you want guaranteed message delivery without backpressure.

channel_capacity

Per-channel capacity configuration. This lets you tweak the channel capacity based on the channel name, and supports glob patterns.

It should be a dict mapping channel name pattern (glob-style) to desired capacity:

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_lite.layers.core.SQLiteChannelLayer",
        "CONFIG": {
            "database": "default",
            "capacity": 100,
            "channel_capacity": {
                "http.request": 200,
                "http.response!*": 10,
                "websocket.send!*": 20,
            },
        },
    },
}

This example sets http.request to 200, all http.response! channels to 10, and all websocket.send! channels to 20.

auto_trim

Whether to automatically clean up expired messages during polling. Defaults to True. When enabled, expired messages and group memberships are periodically removed during normal operation.

"CONFIG": {
    "database": "default",
    "auto_trim": True,
}

You can also manually trigger cleanup:

from channels.layers import get_channel_layer

channel_layer = get_channel_layer()
await channel_layer.clean_expired()

Or use the management command:

python manage.py clean_channels

symmetric_encryption_keys

Pass this to enable optional symmetric encryption of messages. Requires the cryptography package:

pip install channels-lite[cryptography]
CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "channels_lite.layers.core.SQLiteChannelLayer",
        "CONFIG": {
            "database": "default",
            "symmetric_encryption_keys": [SECRET_KEY],
        },
    },
}

symmetric_encryption_keys should be a list of strings, with each string being an encryption key. The first key is always used for encryption; all are considered for decryption, so you can rotate keys without downtime.

Keys should have at least 32 bytes of entropy - they are passed through the SHA256 hash function before being used as an encryption key.

Data is encrypted both at rest in the database and during serialization. The channel and group key names are not encrypted.

serializer_format

Serialization format for messages. Defaults to "json" for the ORM layer and "msgpack" for the AIO layer.

"CONFIG": {
    "database": "default",
    "serializer_format": "json",  # or "msgpack"
}

Note: MessagePack requires msgspec package (included with [aio] extra).

polling_interval

Time in seconds between database polls when waiting for messages. Defaults to 0.1.

"CONFIG": {
    "database": "default",
    "polling_interval": 0.1,
}

Lower values reduce latency but increase database load. Higher values save resources but increase message delivery delay.

polling_idle_timeout

Time in seconds before an idle polling task shuts down. Defaults to 1800 (30 minutes).

"CONFIG": {
    "database": "default",
    "polling_idle_timeout": 1800,
}

Process-specific channels use background polling tasks. These automatically shut down after this timeout to free resources.

AIOSQLite Layer Specific Options

pool_size

Number of connections in the connection pool. Defaults to 10.

"CONFIG": {
    "database": "default",
    "pool_size": 10,
}

Larger pool sizes allow more concurrent operations but use more file descriptors.

Database Configuration

SQLite Performance Settings

For best performance, configure your SQLite database with these settings:

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.sqlite3",
        "NAME": BASE_DIR / "db.sqlite3",
        "OPTIONS": {
            "transaction_mode": "IMMEDIATE",  # Better for write-heavy workloads
            "timeout": 5,  # 5 second busy timeout
            "init_command": (
                "PRAGMA journal_mode=WAL; "      # Write-Ahead Logging for concurrency
                "PRAGMA synchronous=NORMAL; "     # Balanced durability/performance
                "PRAGMA cache_size=10000; "       # ~40MB cache
                "PRAGMA temp_store=MEMORY; "      # Temp tables in memory
                "PRAGMA busy_timeout=5000;"       # 5 second lock timeout
            ),
        },
    },
}

Important: WAL mode (journal_mode=WAL) is required for better concurrency when multiple processes access the database.

Features

  • Full Channels Layer Specification: Supports channels, groups, flush, and capacity enforcement
  • No External Dependencies: Uses SQLite - no Redis installation required
  • Two Implementation Options:
    • Django ORM layer (simple setup, integrates with Django)
    • AIOSQLite layer (better performance, connection pooling)
  • Process-Specific Channels: Unique channel names per process for scaling
  • Group Messaging: Broadcast messages to multiple channels efficiently
  • Message Expiry: Automatic cleanup of expired messages
  • Capacity Enforcement: Backpressure mechanism matching Redis layer behavior
  • Encryption Support: Optional symmetric encryption for sensitive data
  • Database Router: Automatically routes channel tables to correct database

Management Commands

Clean Expired Messages

Remove expired messages and group memberships, and optionally optimize the database:

python manage.py clean_channels

This command performs two maintenance tasks:

  1. Removes expired messages and group memberships from the database
  2. Runs SQLite VACUUM to reclaim disk space and optimize the database

Options:

  • --no-vacuum: Skip the VACUUM operation (only clean expired messages)

Examples:

# Full cleanup with VACUUM
python manage.py clean_channels

# Only clean expired messages, skip VACUUM
python manage.py clean_channels --no-vacuum

Note: The VACUUM operation can take time on large databases and briefly locks the database. Use --no-vacuum if you need to run cleanup frequently or during high-traffic periods.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

channels_lite-0.3.4.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

channels_lite-0.3.4-py3-none-any.whl (20.2 kB view details)

Uploaded Python 3

File details

Details for the file channels_lite-0.3.4.tar.gz.

File metadata

  • Download URL: channels_lite-0.3.4.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for channels_lite-0.3.4.tar.gz
Algorithm Hash digest
SHA256 92d3fad09934f662efaff42c4a50b0e84e4b714b80e6371632b055829aec4a6e
MD5 f4f828969b566067fdd21c813ad8d489
BLAKE2b-256 596f3a4c897917816ec2f73321d8b519bfcab38c16cf9ffe5f050fd375570e93

See more details on using hashes here.

Provenance

The following attestation bundles were made for channels_lite-0.3.4.tar.gz:

Publisher: publish.yml on Tobi-De/channels-lite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file channels_lite-0.3.4-py3-none-any.whl.

File metadata

  • Download URL: channels_lite-0.3.4-py3-none-any.whl
  • Upload date:
  • Size: 20.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for channels_lite-0.3.4-py3-none-any.whl
Algorithm Hash digest
SHA256 60ee6fe60dd01600c14ee54da5c541ca79aacde75520cf04c0cfa34160d680cf
MD5 0205ea5f15b3481632319a42b838b526
BLAKE2b-256 27aa608c4d7c6ecfeace9709f6f215383f9fc083de037c8acf9cc13067411c9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for channels_lite-0.3.4-py3-none-any.whl:

Publisher: publish.yml on Tobi-De/channels-lite

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page