Feature Flags Support with Virto Commerce and Virto Storefront

Overview of Feature Flags Concept

Feature flags, also known as feature toggles or feature switches, are a powerful technique used in software development to enable or disable features in an application or service. They provide developers with the ability to dynamically control the activation and visibility of features at runtime without deploying new code. This allows for safer experimentation, gradual feature rollouts, and targeted feature releases.

Benefits of Using Feature Flags

Integrating feature flags into Virto Commerce and Virto Storefront offers several significant benefits:

  • Modularity: Feature flags enable safe and controlled feature releases by allowing developers to enable or disable features remotely by installing/uninstalling Virto Commerce module.
  • A/B Testing: Feature flags facilitate A/B testing and experimentation by enabling developers to test new features with a subset of users before rolling them out to the entire user base.
  • Rollback Control: In case of issues or unexpected behaviour, feature flags provide the ability to quickly roll back changes by disabling the problematic feature.
  • Configuration Management: Feature flags provide a centralized mechanism for managing feature configurations, making it easier to manage feature variations across different environments.

References

The Hub for Feature Flag Driven Development | FeatureFlags

Architecture

Virto Commerce Platform 3.813+ and Virto Commerce XAPI 3.812+ introduce Public Store Settings. This architecture enables seamless integration of feature flags into Virto Commerce and Virto Storefront.

  • Virto Commerce extended SettingDescriptor with the IsPublic property, indicating that a setting is accessible for client applications via the XAPI.
  • Virto Commerce XAPI extended store query with modules that grant access to Public Store Settings per module.

Example of Creating a Public Property Based on the Google Analytics Module

The following code snippet demonstrates how to create public properties for the Google Analytics module using the extended SettingDescriptor:

public static SettingDescriptor EnableTracking { get; } = new SettingDescriptor
{
    Name = "GoogleAnalytics4.EnableTracking",
    GroupName = "Google Analytics 4",
    ValueType = SettingValueType.Boolean,
    IsPublic = true
};

public static SettingDescriptor MeasurementId { get; } = new SettingDescriptor
{
    Name = "GoogleAnalytics4.MeasurementId",
    GroupName = "Google Analytics 4",
    ValueType = SettingValueType.ShortText,
    IsPublic = true
};

XAPI/GraphQL Schema

query{
  store(storeId: "B2B-store", cultureName: "en-US") {
    storeId
    settings {
      modules { moduleId settings {name value} }
    }
  }
}
{
  "data": {
    "store": {
      "storeId": "B2B-store",
      "settings": {
        "modules": [
          {
            "moduleId": "VirtoCommerce.GoogleEcommerceAnalytics",
            "settings": [
              {
                "name": "GoogleAnalytics4.EnableTracking",
                "value": true
              },
              {
                "name": "GoogleAnalytics4.MeasurementId",
                "value": "GA-B2B-STORE"
              }
            ]
          }
        ]
      }
    }
  }
}

How to Do GraphQL Call in Virto Storefront

In Virto Storefront, you can use GraphQL queries to request modules with public settings. Here’s an example of how to check if the Google Analytics module is installed and retrieve its settings.

In this utility class, we define methods to check if a feature is enabled and to get the value of a feature based on the provided moduleId and featureName . This approach encapsulates feature flag logic and promotes reusability and maintainability in your VueJS application.

class FeatureFlags {
  constructor(modules) {
    this.modules = modules;
  }

  isEnabled(moduleId, featureName) {
    const module = this.modules.find(module => module.moduleId === moduleId);
    if (module) {
      const feature = module.settings.find(setting => setting.name === featureName);
      if (feature && feature.value === true) {
        return true;
      }
    }
    return false;
  }

  getValue(moduleId, featureName) {
    const module = this.modules.find(module => module.moduleId === moduleId);
    if (module) {
      const feature = module.settings.find(setting => setting.name === featureName);
      if (feature && feature.value !== undefined) {
        return feature.value;
      }
    }
    return null;
  }

  isEnabled(moduleId) {
    const module = this.modules.find(module => module.moduleId === moduleId);
    return !!module;
  }
}

In this example, the GraphQL query retrieves store settings, including modules and their settings. The returned data can then be processed to determine if the Google Analytics module is installed and retrieve its settings.

// Instantiate FeatureFlags with modules data
const featureFlags = new FeatureFlags(result.data.store.settings.modules);

// Check if a module is enabled
const isModuleEnabled = featureFlags.isEnabled("VirtoCommerce.GoogleEcommerceAnalytics");

// Check if a feature is enabled
const isTrackingEnabled = featureFlags.isEnabled("VirtoCommerce.GoogleEcommerceAnalytics", "GoogleAnalytics4.EnableTracking");

// Get feature value
const measurementId = featureFlags.getValue("VirtoCommerce.GoogleEcommerceAnalytics", "GoogleAnalytics4.MeasurementId");

Integrating feature flags with Virto Commerce and Virto Storefront using public store settings and GraphQL queries provides developers with a flexible and efficient way to manage feature variations and configurations in their applications.

Summary

Implementing feature flags with Virto Commerce and Virto Storefront provides developers with a flexible and efficient way to manage feature variations and configurations in their applications. By leveraging public store settings and GraphQL queries, developers can easily control feature activation and visibility at runtime, enabling safer experimentation, gradual rollouts, and targeted releases.

This is the version working in the Theme:

import type { ModuleSettingsType } from "@/core/api/graphql/types";

class FeatureFlags {
  private modules: ModuleSettingsType[];

  constructor(modules: ModuleSettingsType[]) {
    this.modules = modules;
  }

  isFeatureEnabled(moduleId: string, featureName: string) {
    const module = this.modules.find((m) => m.moduleId === moduleId);
    if (module) {
      const feature = module.settings.find(setting => setting.name === featureName);
      if (feature && feature.value === true) {
        return true;
      }
    }
    return false;
  }

  getValue(moduleId: string, featureName: string) {
    const module = this.modules.find(m => m.moduleId === moduleId);
    if (module) {
      const feature = module.settings.find(setting => setting.name === featureName);
      if (feature && feature.value !== undefined) {
        return feature.value;
      }
    }
    return null;
  }

  isModuleEnabled(moduleId: string) {
    const module = this.modules.find(m => m.moduleId === moduleId);
    return !!module;
  }
}

export default FeatureFlags;

I’m updating Virto Commerce Settings as Feature Flags topic with latest status:

Overview

Virto Commerce Platform uses its Settings subsystem as a first-class mechanism for feature flag management. Rather than requiring a separate feature-flag service, settings provide a unified, API-driven, DB-backed, and now config-file-overridable way to toggle, configure, and gate behavior across the platform backend, Admin UI, and storefronts — per global scope or per tenant (Store).

The Settings system spans four layers of resolution, applied in priority order:

Force (appsettings / env-var override)
  → Database (Admin UI or API-saved value)
    → Default config override (appsettings DefaultValue)
      → Descriptor default (code/module manifest)

This means that operators can hard-lock a flag at deploy time (CI/CD, Virto Cloud env vars), merchants can self-serve toggle features via the Admin UI, and module authors define safe defaults in code — all without conflicts.

Features

  • Typed setting descriptors — Modules declare settings as strongly typed descriptors (bool, string, integer, decimal, secureString, json) with allowed values, default values, display metadata, and an IsPublic flag that exposes them to the XAPI/Storefront layer.
  • Global and Store (tenant) scopes — A setting can be set globally for all stores or overridden at the individual Store level, enabling per-tenant feature flag behavior equivalent to what platforms like Commercetools offer through custom types.
  • Admin UI management — All registered settings appear in the Platform Manager under Browse → Settings, grouped by module. Operators can edit values, see current effective values, and reset a setting to its default via a dedicated “Reset to default” action introduced in PR #2973.
  • REST API access — Settings are readable and writable via GET/PUT api/platform/settings and GET api/platform/settings/values/{name}, enabling automation, CI pipelines, and integrations.
  • XAPI / Storefront exposure — Settings marked IsPublic: true are served through the GraphQL XAPI layer, making frontend feature flags accessible to Vue Storefront or any headless client without a backend proxy.
  • appsettings.json / environment-variable overrides (Released Feb 2026) — A new ISettingsOverrideProvider interface and its default implementation ConfigurationSettingsOverrideProvider let operators inject both forced current values (read-only, bypasses DB) and default value overrides directly from appsettings.json or environment variables. Forced settings are idempotent: on save, SettingsManager skips them and removes any conflicting DB entries automatically.
  • Virto Cloud compatibility — Because Virto Cloud does not support dots in environment variable names, the override provider resolves setting names with dots converted to underscores as a fallback (e.g. GoogleAnalytics4_MeasurementId resolves to GoogleAnalytics4.MeasurementId).

Scenarios and Code Snippets

1. Declaring a Feature Flag in a Module

Register a boolean setting descriptor in your module’s Module.cs:

csharp

// Module.cs — Initialize
public void Initialize(IServiceCollection serviceCollection)
{
    var settings = new[]
    {
        new SettingDescriptor
        {
            Name = "Frontend.Checkout.EnableFastCheckout",
            GroupName = "Checkout|General",
            ValueType = SettingValueType.Boolean,
            DefaultValue = false,
            IsPublic = true,   // expose to XAPI / Storefront
            Title = "Enable Fast Checkout",
            Description = "Skips the address step for returning customers."
        }
    };
    serviceCollection.AddSettings(settings);
}

2. Reading a Feature Flag at Runtime (Backend)

csharp

public class CheckoutService
{
    private readonly ISettingsManager _settings;

    public CheckoutService(ISettingsManager settings)
    {
        _settings = settings;
    }

    public async Task<bool> IsFastCheckoutEnabled(string storeId)
    {
        // Resolves: Force → DB → DefaultValue override → Descriptor default
        return await _settings.GetValueAsync<bool>(
            "Frontend.Checkout.EnableFastCheckout",
            storeId);   // pass null for global scope
    }
}

3. Overriding Settings via appsettings.json

json

"VirtoCommerce": {
  "Settings": {
    "Override": {
      "CurrentValue": {
        "Global": {
          "Platform.SendDiagnosticData": true,
          "GoogleAnalytics4.MeasurementId": "GTM-XX-XXX",
          "VirtoCommerce.Core.General.Languages": ["en-US", "de-DE"]
        },
        "Tenants": {
          "Store": {
            "B2B-store": {
              "Frontend.Checkout.EnableFastCheckout": true
            }
          }
        }
      },
      "DefaultValue": {
        "Global": {
          "Orders.OrderAdjustInventory": true,
          "Frontend.Checkout.EnableFastCheckout": false
        }
      }
    }
  }
}

CurrentValue entries are forced — they are read-only in Admin UI and overwrite any DB value. DefaultValue entries change the default that appears when no DB value has been saved, without locking out Admin UI edits.

4. Overriding via Environment Variables (Virto Cloud / Docker)

Standard ASP.NET Core double-underscore path notation:

bash

# Standard (dots supported)
VirtoCommerce__Settings__Override__CurrentValue__Global__GoogleAnalytics4.MeasurementId=G-PSW1MY7HB4

# Virto Cloud (dots not supported — use underscores, resolved automatically)
VirtoCommerce__Settings__Override__CurrentValue__Global__GoogleAnalytics4_MeasurementId=G-PSW1MY7HB4

# Per-store flag
VirtoCommerce__Settings__Override__CurrentValue__Tenants__Store__B2B-store__Frontend_Checkout_EnableFastCheckout=true

5. Querying Public Settings from XAPI (Storefront / Frontend)

graphql

query {
  storeSettings(storeId: "B2B-store") {
    name
    value
  }
}

Any SettingDescriptor with IsPublic = true is returned. The resolved effective value (after Force → DB → Default chain) is what the storefront receives.

6. REST API — Read & Write a Setting

http

# Read current effective value
GET /api/platform/settings/values/Frontend.Checkout.EnableFastCheckout

# Save a new value (Admin or automation)
PUT /api/platform/settings
[
  {
    "name": "Frontend.Checkout.EnableFastCheckout",
    "value": "true",
    "valueType": "Boolean"
  }
]

What’s In Progress (26Q1)

Module Version Metadata in Store Settings

A companion feature extends the store GraphQL response shape to include installed module version information alongside store settings. So that, Frontend receives a complete capability manifest (store settings, installed modules with versions, feature flags) and can check compatibility level with backend and plan all subsequent GraphQL queries — including or excluding optional features like white labelling, customer reviews, quotes, etc.

External Setting Source — Frontend can define platform settings

This upcoming user story extends the Settings Registry to accept setting definitions from external sources — specifically from X-Frontend storefronts that publish their own settings_schema.json asset file. The architecture introduces:

+--------------------+
|  Backend modules   |
|  (code descriptors)|
+---------+----------+
          |
          v
    +-----------+         +-----------------------------------------------+
    | Registry  |<--------| External definitions of Store Settings (DB)   | -----> HTTP http://mystore.com/config/settings_schema.json
    | (merged)  |         | (from X-Frontend ingestion)                   |
    +-----+-----+         +-----------------------------------------------+
          |                       Assets > settings_schema.json
          |
          v
+------------------+------------------+
|        Settings Resolver            |
|  Force cfg → DB → Default cfg →    |
|  Descriptor default + provenance    |
+-----------+--------------------------+
            |
  +---------+---------+
  |                   |
  v                   v
Admin UI          XAPI/Storefront
(edit/override)   (public effective)

Key capabilities being designed:

  • X-Frontend publishes a settings_schema.json to its asset store describing its own feature flags and configuration schema (analogous to Commercetools Custom Types).
  • The platform ingests this schema and registers those settings in the merged Registry alongside backend module descriptors.
  • Ingested settings are persisted in DB as “externally defined” Store settings with full provenance tracking.
  • Admin UI allows operators to edit these settings just like native ones.
  • XAPI serves effective values to the storefront without any custom backend code.
  • A dedicated HTTP endpoint (/config/settings_schema.json) acts as the schema contract between frontend and platform.

Roadmap Features for Next Release

We are always open to your ideas, share them here, and I will add them into Virto Commerce roadmap.