Applications often have settings that can be either enabled or disabled, such as notifications, dark mode, automatic saving, or access to beta features. When several of these settings are stored as flags in a single integer column, checking or changing one setting means working with a specific bit in that value.
SQL Server 2022 provides GET_BIT() and SET_BIT() for this type of work. GET_BIT() can check the current value of an individual bit, while SET_BIT() can change that bit without affecting the other positions. In this article, we'll use both functions to manage feature flags stored in a table. We'll start by reading the settings that are currently enabled for each user, then change individual features and verify the updated values.
Setting Up the Feature Flags
For this example, we'll store four application settings in a single FeatureFlags column. Each setting is assigned its own bit position:
- Bit position 0 represents Notifications.
- Bit position 1 represents Dark Mode.
- Bit position 2 represents Auto Save.
- Bit position 3 represents Beta Features.
The UserSettings table stores the user name together with the current feature flag value. The following script creates the table and adds three users with different settings enabled.
CREATE TABLE UserSettings
(
UserID INT PRIMARY KEY,
UserName VARCHAR(50),
FeatureFlags INT
);
INSERT INTO UserSettings
VALUES
(1, 'Liam Wilson', 3),
(2, 'Olivia Taylor', 4),
(3, 'Noah Anderson', 9);The value stored in FeatureFlags represents a combination of enabled settings. Liam's value of 3 enables Notifications and Dark Mode. Olivia's value of 4 enables Auto Save, while Noah's value of 9 enables Notifications and Beta Features.
With the sample data in place, we can now read the individual settings stored inside each FeatureFlags value.
Reading the Current Settings
The FeatureFlags column stores several settings in one value, but the number itself does not immediately show which features are enabled. To display each setting separately, we can use GET_BIT() to read the value at each bit position.
In the following query, GET_BIT() is called four times for each user. The first argument is the FeatureFlags value from the current row, and the second argument identifies the bit position to check. Each result is given a column name that matches the feature it represents.
SELECT
UserID,
UserName,
FeatureFlags,
GET_BIT(FeatureFlags, 0) AS Notifications,
GET_BIT(FeatureFlags, 1) AS DarkMode,
GET_BIT(FeatureFlags, 2) AS AutoSave,
GET_BIT(FeatureFlags, 3) AS BetaFeatures
FROM UserSettings;The output makes the stored values easier to understand. Liam's FeatureFlags value of 3 should show Notifications and Dark Mode as enabled. Olivia's value of 4 should show only Auto Save as enabled, while Noah's value of 9 should show Notifications and Beta Features as enabled.

Instead of interpreting the bitmask value manually, the query presents each feature as a separate 0 or 1 value.
Changing and Saving a Feature
Suppose Liam wants to enable Auto Save, which is stored at bit position 2. He currently has a FeatureFlags value of 3, with Notifications and Dark Mode enabled.
The following query uses SET_BIT() to calculate the new value. The first argument passes the current FeatureFlags value, the second identifies bit position 2, and the third sets that position to 1. The WHERE clause limits the query to UserID = 1.
SELECT
UserID,
UserName,
FeatureFlags AS CurrentFlags,
SET_BIT(FeatureFlags, 2, 1) AS NewFlags
FROM UserSettings
WHERE UserID = 1;Setting bit position 2 to 1 should produce a new value of 7, so the result should show 3 in CurrentFlags and 7 in NewFlags.

The query returns 7 as the new value, but Liam's stored FeatureFlags value is still 3. To save the change, we can use the same SET_BIT() expression in an UPDATE statement.
UPDATE UserSettings SET FeatureFlags = SET_BIT(FeatureFlags, 2, 1) WHERE UserID = 1;
The SET clause stores the value returned by SET_BIT() back in the FeatureFlags column, while the WHERE clause ensures that only Liam's row is updated.
We can then use GET_BIT() to check the Auto Save position.
SELECT
UserID,
UserName,
FeatureFlags,
GET_BIT(FeatureFlags, 2) AS AutoSave
FROM UserSettings
WHERE UserID = 1;Liam's FeatureFlags value should now be 7, and AutoSave should return 1.

Disabling a Feature
The same approach can be used when a feature needs to be turned off. Noah currently has a FeatureFlags value of 9, which means Notifications and Beta Features are enabled. Suppose we want to disable Beta Features while leaving his other settings unchanged.
Beta Features uses bit position 3. In the following statement, SET_BIT() changes that position to 0 and stores the updated value back in the FeatureFlags column. The WHERE clause limits the update to Noah's row.
UPDATE UserSettings SET FeatureFlags = SET_BIT(FeatureFlags, 3, 0) WHERE UserID = 3;
We can then check all four feature positions for Noah rather than looking only at the updated bit.
SELECT
UserID,
UserName,
FeatureFlags,
GET_BIT(FeatureFlags, 0) AS Notifications,
GET_BIT(FeatureFlags, 1) AS DarkMode,
GET_BIT(FeatureFlags, 2) AS AutoSave,
GET_BIT(FeatureFlags, 3) AS BetaFeatures
FROM UserSettings
WHERE UserID = 3;Noah's original value of 9 should change to 1. The result should show BetaFeatures = 0, while Notifications remains 1. Dark Mode and Auto Save remain disabled.

Updating Only the Rows That Need a Change
So far, we have changed a feature for one user at a time. GET_BIT() can also be used in the WHERE clause of an UPDATE statement to find rows where a particular feature is currently disabled. Suppose we want to enable Auto Save for every user who does not already have it enabled. Auto Save uses bit position 2. In the following statement, GET_BIT() checks that position for each row and selects only users where it returns 0. SET_BIT() then changes the same position to 1 for those rows.
UPDATE UserSettings SET FeatureFlags = SET_BIT(FeatureFlags, 2, 1) WHERE GET_BIT(FeatureFlags, 2) = 0;
At this point in our sample data, Liam already has Auto Save enabled from the earlier update, and Olivia had it enabled from the beginning. Noah does not have Auto Save enabled, so only his row should be updated. His current FeatureFlags value is 1 after Beta Features was disabled, and enabling Auto Save should change that value to 5.
We can check the Auto Save setting for all users with the following query.
SELECT
UserID,
UserName,
FeatureFlags,
GET_BIT(FeatureFlags, 2) AS AutoSave
FROM UserSettings;
The result should show AutoSave = 1 for all three users. GET_BIT() identifies the rows where Auto Save is disabled, and SET_BIT() enables it for those rows.
Final Thoughts
Storing several on/off settings in a single bitmask can keep the data compact, but individual settings still need to be read and changed when users update their preferences.
In this article, we used GET_BIT() to read individual feature flags and SET_BIT() to change them without rebuilding the complete bitmask value. We also used both functions in the same update, where GET_BIT() identified the rows that needed a change and SET_BIT() updated the selected feature.
Using the two functions together provides a practical way to manage individual settings stored in a bitmask while leaving the other settings unchanged.