Skip to main content

Django FeatureVault

PyPI PyPI - Python Version PyPI - License

Feature Flag Framework for Django.

Installation

python -m pip install django-featurevault

First, add django_featurevault to your INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    "django_featurevault",
]

Next, add FeatureContextMiddleware to your MIDDLEWARE list:

MIDDLEWARE = [
    # ...
    "django_featurevault.middleware.FeatureContextMiddleware",
]

Finally, configure your feature flags in settings.py:

FEATURE_FLAGS = {
    "default": {
        "BACKEND": "django_featurevault.backends.settings.SettingsBackend",
        "OPTIONS": {
            "FLAGS": {
                "GLOBAL_BANNER": True,
                "STAFF_DASHBOARD": {
                    "enabled": True,
                    "conditions": {
                        "groups": [
                            {
                                "properties": [
                                    {"key": "is_staff", "operator": "exact", "value": True}
                                ]
                            }
                        ]
                    },
                },
                "NEW_CHECKOUT": {
                    "enabled": True,
                    "conditions": {
                        "groups": [
                            {"rollout_percentage": 50}
                        ]
                    },
                },
            }
        },
    }
}

Backends

Few backends are included by default:

  • django_featurevault.backends.settings.SettingsBackend: Reads feature flags directly from settings.FEATURE_FLAGS.
  • django_featurevault.backends.dummy.DummyBackend: In-memory backend for testing.

Custom Backends

You can create custom storage backends by subclassing BaseFeatureBackend and implementing get_feature and get_all_features:

from typing import Any
from django_featurevault.backends.base import BaseFeatureBackend


class CustomRedisBackend(BaseFeatureBackend):
    def __init__(self, alias: str = "default", **options: Any) -> None:
        super().__init__(alias=alias, **options)
        # Initialize client connections using options passed from settings
        self.redis_url = options.get("URL", "redis://localhost:6379/0")

    def get_feature(self, feature_name: str, default: Any = False) -> dict[str, Any]:
        """
        Fetch feature configuration dictionary by name.
        Must return a dict containing at minimum:
        {"enabled": bool, "conditions": dict}
        """
        # Fetch from your storage engine...
        return {
            "enabled": True,
            "conditions": {},
        }

    def get_all_features(self) -> dict[str, dict[str, Any]]:
        """Fetch all feature definitions for bulk evaluation."""
        return {}

Point to your custom backend in settings.py:

FEATURE_FLAGS = {
    "default": {
        "BACKEND": "my_app.backends.CustomRedisBackend",
        "OPTIONS": {
            "URL": "redis://127.0.0.1:6379/1",
        },
    }
}

Usage

Checking flags in views

Import feature and call is_enabled:

from django.shortcuts import render
from django_featurevault import feature


def home_view(request):
    if feature.is_enabled("NEW_CHECKOUT"):
        return render(request, "new_checkout.html")
    return render(request, "old_checkout.html")

If a flag is not defined, is_enabled returns False by default. You can change this using the default parameter:

feature.is_enabled("UNKNOWN_FLAG", default=True)

Passing explicit context

You can pass a custom context dictionary directly into is_enabled:

feature.is_enabled("BETA_FEATURE", context={"plan": "enterprise", "country": "IN"})

Background tasks and testing context

To evaluate feature flags in Celery workers, cron jobs, or tests where no HTTP request exists, use the context manager:

from django_featurevault import feature

with feature.context(user_id="user_101", is_staff=True):
    if feature.is_enabled("STAFF_DASHBOARD"):
        ...

Conditions and Targeting

Flags defined as dictionaries support targeting rules via conditions.

"FEATURE_NAME": {
    "enabled": True,
    "conditions": {
        "groups": [
            # Group 1: Enabled for internal staff
            {
                "properties": [
                    {"key": "is_staff", "operator": "exact", "value": True}
                ],
            }
            # OR Group 2: Enabled for 20% of beta users in India
            {
                "properties": [
                    {"key": "country", "operator": "exact", "value": "IN"},
                    {"key": "plan", "operator": "exact", "value": "beta"}
                ],
                "rollout_percentage": 20,
            }
        ]
    },
}
  • groups: Evaluated with OR logic (if any group matches, the flag is enabled).
  • properties within a group: Evaluated with AND logic (all properties in the group must match).
  • rollout_percentage: A percentage between 0 and 100 that uses sticky hashing against the user or device ID.

Supported operators

  • exact: Matches exact equality (==).
  • is_not: Matches inequality (!=).
  • in: Checks values in a list (value in [...]).
  • icontains: Case-insensitive substring match.

Automatically resolved user fields

When evaluating against an authenticated Django user, the following context keys are resolved automatically:

  • user_id, id, pk: The user's primary key (user.pk).
  • username: The user's username (getattr(user, user.USERNAME_FIELD)).
  • django_group: Group names the user belongs to (user.groups.values_list("name", flat=True)).
  • Any standard or custom attribute on the user model (like is_staff, is_superuser, email).

Cookie Configuration

FeatureContextMiddleware automatically sets an anonymous device cookie for sticky rollouts when users are not logged in.

You can customize the cookie name and options in settings.py:

FEATURE_FLAGS = {
    "CLIENT_ID_COOKIE": "ff_client_id",
    "COOKIE_OPTIONS": {
        "max_age": 30 * 24 * 60 * 60,
        "httponly": True,
        "samesite": "Lax",
    },
}

API Endpoint

To expose evaluated feature flags to frontend clients as JSON, include the URLs in your urls.py:

from django.urls import include, path

urlpatterns = [
    # ...
    path("features/", include("django_featurevault.urls")),
]

This registers GET /features/api/flags/, and returns a JSON map of all evaluated flags:

{
  "GLOBAL_BANNER": {"enabled": true},
  "STAFF_DASHBOARD": {"enabled": false},
  "NEW_CHECKOUT": {"enabled": true}
}

Example Project

An example project is included in the example/ directory.

Download files

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

Source Distribution

django_featurevault-0.1.0.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

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

django_featurevault-0.1.0-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file django_featurevault-0.1.0.tar.gz.

File metadata

  • Download URL: django_featurevault-0.1.0.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.3

File hashes

Hashes for django_featurevault-0.1.0.tar.gz
Algorithm Hash digest
SHA256 c03c5128fec5c68e298c57d79093592d16544bd8bba5940cde27252b03f414c9
MD5 88ec5675d3a30a80f3cd71e7a49106cb
BLAKE2b-256 bf7898c861e60e50130fd1648c09b68ce2382e3a3f67d3fa959a0f87611ed680

See more details on using hashes here.

File details

Details for the file django_featurevault-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_featurevault-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 38f87de89169f94e8c81d79d65de42785b6935045da74c61ede6c10e5fdd3d31
MD5 5e15e3ab7315d741ca70cb6e8afef155
BLAKE2b-256 50acbda0d0f54aff42e291979c71b036ddcc40491e28252ee0ea09fbcdcccbd0

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page