Feature Flags Framework for Django

Hello everyone,

Over the past few months, I, along with @nanorepublica, researched what a Feature Flag framework for Django could look like. For this we researched django-waffle, django-flags and some other paid feature flag frameworks including PostHog, LaunchDarkly and Unleash to see what a good feature flag APIs should offer.

Specifically, we wanted to address the friction around dynamic state in django-waffle @nessita mentioned in the Experimental Framework thread.

After researching, we built django-featurevault which addresses this by using contextvars to decouple flag evaluation from the request object. This allows flags to be checked consistently across views, async code, and background workers without passing an HttpRequest everywhere, and it also has other features like pluggable backends, deterministic percentage rollouts with flexible targeting rules.

Links:

I would love for all of you to try it out and share your feedback.

I didn’t exactly follow the experimental framework thread, so sorry if this came up already. Did you look at OpenFeature? From what I gather it is becoming more and more of a standard – ie all the paid feature flags frameworks seem to offer OpenFeature providers for python so you can easily access and swap them out. May the OpenFeature python SDK offers already all that is needed and we just need a bit of plumbing for that?

We missed this in our research! From a very brief look, it looks like it could be something we could adopt, I think it has all the features we initially considered and more.

Long term, if we wanted an feature flag API in Django, I wonder if it’s a dependency we would want to include or not? However this then speaks to another aspect of the research we explored in terms of using python packages extras to a greater extent.

This is something I’m going to explore and ponder. :thinking:

To be honest, I’m not sure where this fits. For community usage there are plenty of popular, well-designed solutions that have been maintained for years. And if we’re talking about Django’s internal usage, it feels like over-engineering . a simple True/False dataclass should be enough.

I’d highly recommend looking at GitHub - evo-company/featureflags-py: FeatureFlags service client in Python · GitHub . it’s a well-designed feature-flag client + server. It provides a client based on context vars + conditions, already ships with backends (static, dummy and a separate HTTP server).

It’s been in production for many years and works perfectly under high load.

I guess I agree, when it comes to experimental features in Django something more simplistic is in order. When it comes to feature flags for enduser features I rather not have us reinvent the wheel and use existing solutions (especially since feature flags can get rather complicated – like enable it for 50% of the users in Europe etc).

Thanks for sharing this @prafulgulani. Is there a summary of the features in this package compared to others? What’s novel, different or the same across the existing options?

@apollo13 @Arfey is it worth looking at this from a Django Tasks-esque angle? Where Django defines the contract/interface for other tools to implement. Is there a benefit in allowing various third-party packages communicate feature flags in a standardized way?

Django Tasks solves one important problem for third-party packages: how to run background tasks without caring which tool the end user picks (Celery, Dramatiq, etc.).

Third-party packages don’t have that problem with flags, and they don’t need a contract. There’s already a widespread pattern for managing this. If I need a global setting, I just add it to settings:

<MY_PACKAGE>_<FEATURE_NAME>_ENABLED = True

Easy peasy :slightly_smiling_face:

On top of that, let’s say we provide a feature-flags abstraction. Now the user can use a runtime backend to change settings. Then the author of a third-party library has to worry about reinitializing the package if it caches state based on the flag.

Personally I think the answer is probably no. Tasks gives you an abstraction about which “provider” (celery etc) you wanna use. OpenFeature does the same already, so you’d abstract around an abstraction. In the end the main question is: How much work do we want to force on providers to implement a backend for Django when we could just use the existing vendor-agnostic (quasi)-standards. Simply recommending and using OpenFeature for feature flags (probably not experiments, ymmv) might save much time everywhere.

EDIT:// As another example if Django wouldn’t have an ORM nowadays would we write it on our own or see if we could at least use the low level sqlalchemy utilities and wrap around those?

Maybe? If so, it feels like that’s an indication we’ve swung away from what makes Django Django. Mainly the opinionated integrations between layers that allow for quick implementations that accomplish a lot. The ORM and Admin are both extremely popular utilities in Django, but they go against what we push for in a lot of cases now.

1 Like

@CodenameTim

If we’re talking about end-user usage (not third-party providers), a few things matter for feature flags:

  • They have to be changeable at runtime, without a redeploy.
  • The flag store should live outside the app it controls. If a feature causes downtime, you can’t open the admin to disable it, because the admin is down too. A separate instance avoids that.
  • They have to be easy to integrate across the whole product. The moment you have more than one service, a Django-only, DB-backed solution becomes a problem.

A built-in feature flags system doesn’t fit that. I understand the motivation to cover every user need, but feature flags in core Django don’t feel like the right place. It looks more like a restriction than an opportunity.

:slightly_smiling_face:

A built-in feature flags system would have settings or the db as default backend (the usefulness of that is questionable) and would allow external providers like flagd as backend. So a built-in feature flag system could very well tick all boxes. The main question to me is if it is worth the effort to reimplement OpenFeature when we could depend on OpenFeature and then just write a database-backed backend with an admin UI for simple cases.

1 Like