Skip to content

[DEPR]: Add FEATURES = FeaturesProxy(...) to your django settings #37345

Closed

Description

@wgu-ram-chandra

RFC Start Date

N/A — Already Accepted

Target Plan Accepted Date

N/A — Already Accepted

Target Transition Unblocked Date

Immediately — Transition Already Unblocked

Earliest Breaking Changes Unblocked Date

2025-09-18

Rationale

In Django settings, the FEATURES dictionary has traditionally been used as a mutable container for feature flags. This often leads to confusion between top-level settings and dictionary keys, and makes it difficult to manage operator configurations properly.

To improve clarity and long-term maintainability, we are moving toward treating all feature flags as top-level Django settings, and deprecating the use of FEATURES for this purpose.

Description

Breaking change:
Operators who maintain custom settings modules that write to FEATURES must add the following snippet at the top of their settings file(s) to ensure backwards compatibility:

try:
    from openedx.core.lib.features_setting_proxy import FeaturesProxy
    FEATURES = FeaturesProxy(globals())
except ImportError:
    pass

This allows existing references to FEATURES[...] to continue functioning while we transition off of it.

Future changes (timeline TBD):

  • Writes to FEATURES (e.g: FEATURES["SOME_FLAG"] = True) will no longer be supported.
  • Reads from FEATURES (e.g: if FEATURES.get("SOME_FLAG"):) should be replaced by top-level settings access (e.g: if settings.SOME_FLAG:).
  • Reads and writes will continue to work temporarily, but new code should consistently use top-level settings.

Operator Guidance

  • Before 2025-09-18, add the FeaturesProxy(globals()) snippet above to any custom settings modules that write to FEATURES.
  • No other immediate changes are required. Future deprecation notices will provide clear instructions when read/write support is removed.

Activity

  1. added
    deprProposal for deprecation & removal per OEP-21
    on Sep 10, 2025
  2. changed the title [-][DEPR]: Deprecate direct writes to FEATURES in Open edX settings[/-] [+][DEPR]: Deprecate writes to FEATURES in Open edX settings[/+] on Sep 10, 2025
  3. changed the title [-][DEPR]: Deprecate writes to FEATURES in Open edX settings[/-] [+][DEPR]: Transitioning FEATURES writes to FeaturesProxy[/+] on Sep 10, 2025
  4. robrap commented on Sep 12, 2025

    @robrap
    Contributor

    @wgu-ram-chandra @kdmccormick:

    1. I'm not clear on the plan. Since we already duplicated the settings to the top-level (expand phase), can you confirm that we'd be ready to contract (i.e. remove the FEATURES dict) as soon as the proxy PR lands?
    2. [inform] I think from @Akanshu-2u's latest test, the FEATURES dict continues to be the source of truth when both sets of settings exist. From our end, I think the settings need to match, so it really shouldn't matter. But just ensuring that that is what you want.
  5. kdmccormick commented on Sep 12, 2025

    @kdmccormick
    Member

    Sorry @robrap , we have been trying to generalize the guidance to work for all operators, but it's been challenging to write instructions that are coherent across the possibility matrix of (Master vs. NamedRelease) X (production.py+yaml vs custom module).

    Let me try again. Here is what master-based operators should know:

    • Before the PR lands:
      • Only the FEATURES keys will matter. The top-level settings will be ignored.
      • The FeaturesProxy snippet is a no-op (and we encourage operators to add it now to any custom settings modules they have).
    • After the PR lands on ~9/18:
      • The FEATURES keys will take precedence, but if they are not present, the top-level settings will also work.
        • thus, it is safe and encouraged to remove the FEATURES keys at this point.
      • The FeaturesProxy snippet is required for all custom django settings modules.
        • For operators that just use the upstream production.py, they do not need to do anything. The PR will add the required FeatureProxy snippet.
    • On some future date after the Ulmo cutoff, exact date TBD/TBC:
      • the FEATURES dict will become a no-op
      • the FeaturesProxy snippet will become a no-op again (and will remain that way forever, so we recommend removing it)

    Does that make sense?

  6. robrap commented on Sep 12, 2025

    @robrap
    Contributor

    Thanks for clarifying @kdmccormick. We're mostly ready for the change, and @Akanshu-2u will hopefully should have a fix in devstack for Monday. We can discuss Monday if it makes sense to merge more quickly, to benefit you and us. I'm not sure if MIT needs any additional time? Thanks again.

  7. kdmccormick commented on Sep 12, 2025

    @kdmccormick
    Member

    Great. Let us know if you're ready early, and I'll check with MIT ODL separately.

  8. moved this from Draft to Transition Unblocked in DEPR: Deprecation & Removalon Sep 16, 2025
  9. changed the title [-][DEPR]: Transitioning FEATURES writes to FeaturesProxy[/-] [+][DEPR]: Add `FEATURES = FeaturesProxy(...)` to your django settings[/+] on Sep 16, 2025
  10. moved this from Transition Unblocked to Breaking Changes Unblocked in DEPR: Deprecation & Removalon Sep 18, 2025
  11. feanil commented on Sep 18, 2025

    @feanil
    Contributor

    The relevant PR has now merged.

  12. moved this from Breaking Changes Unblocked to Plan Completed in DEPR: Deprecation & Removalon Sep 18, 2025
  13. kdmccormick commented on Sep 29, 2025

    @kdmccormick
    Member
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    deprProposal for deprecation & removal per OEP-21

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions