Behavior Flags Framework
Relevant source files
The following files were used as context for generating this wiki page:
The Behavior Flags Framework is a mechanism within dbt-common designed to manage functional changes and deprecations across dbt packages and adapters. It allows developers to introduce new behaviors that are initially disabled by default, providing users a "bake-in" period to opt-in via configuration before the new behavior becomes the standard. This framework ensures that breaking changes are communicated effectively through structured warnings and documentation links.
Sources: dbt_common/behavior_flags.py:17-38, CHANGELOG.md:193-195
Core Architecture and Components
The framework is built around three primary classes that handle the definition, rendering, and access of behavior flags. It leverages the dbt event system to fire warnings when a user is impacted by a behavior that is currently turned off.
Behavior Configuration Components
| Component | Type | Description |
|---|---|---|
BehaviorFlag | TypedDict | The raw configuration schema for a flag, including name, default value, and documentation. |
BehaviorFlagRendered | Class | The runtime instance of a flag that handles evaluation logic and event firing. |
Behavior | Class | A container for a collection of flags, providing dot-notation access for developers. |
Sources: dbt_common/behavior_flags.py:13-113
Class Relationship Diagram
The following diagram illustrates how the Behavior container manages multiple BehaviorFlagRendered instances derived from BehaviorFlag configurations.
Sources: dbt_common/behavior_flags.py:13-138
Evaluation and Event Logic
The framework is designed to be "noisy" by default when a feature is disabled, but only once per execution. When a developer checks the value of a flag (e.g., if adapter.behavior.my_flag:), the framework evaluates the user's settings.
Evaluation Flow
- Setting Retrieval: The system checks for a user override. If none exists, it uses the flag's
defaultvalue. - Event Firing: If the resulting setting is
Falseand the flag has not yet "fired" during this run, aBehaviorChangeEventis triggered. - State Management: The
firedproperty is set toTrueto prevent duplicate warnings in the logs. - No-Warn Access: Developers can access the setting via
.no_warnto check the value without triggering the warning event.
Configuration Schema
Every behavior flag must provide context to the end user. The framework enforces that at least a description or a docs_url is provided during initialization to ensure users can make informed decisions about enabling flags.
BehaviorFlag Field Definitions
- name: The unique identifier for the flag, used in
dbt_project.yml. - default: The boolean default state. Usually
Falsefor new features during the transition period. - source: The module source of the flag. If not provided, it defaults to the calling module name using
inspect.stack(). - description: A message explaining the behavior controlled by the flag.
- docs_url: A link to documentation (defaults to the dbt behavior changes reference page).
Sources: dbt_common/behavior_flags.py:13-38, dbt_common/behavior_flags.py:86-97
Integration with Event System
The framework uses a specific event type, BehaviorChangeEvent, which inherits from WarnLevel. This ensures that behavior warnings are captured by dbt's logging and event streams.
BehaviorChangeEvent Structure
- Code:
D000 - Message: Includes the description and instructions on how to opt-in via
dbt_project.ymlby setting the flag toTrue. - Formatting: Uses the
warning_tagutility for consistent CLI output.
Sources: dbt_common/events/types.py:46-56
Suppression of Warnings
The WarnErrorOptions and WarnErrorOptionsV2 utility classes provide mechanisms to silence specific events, including BehaviorChangeEvent. Users can configure these options to prevent deprecation warnings from appearing in the console or being treated as errors.
Sources: dbt_common/helper_types.py:65-126, tests/unit/test_helper_types.py:126-150
Implementation Example
The framework supports both Python and Jinja environments for checking flags.
# Python implementation
if adapter.behavior.my_flag:
# Executes if flag is True (user opted-in or default became True)
do_new_logic()
# Silently checking flag value
if adapter.behavior.my_flag.no_warn:
# Checking value without triggering D000 event
pass
{# Jinja implementation #}
{% if adapter.behavior.my_flag %}
-- New logic here
{% endif %}
Sources: dbt_common/behavior_flags.py:102-121
The Behavior Flags Framework provides a standardized path for evolving the dbt ecosystem while maintaining backward compatibility and providing clear migration paths for users through the automated event and warning system.