Implementations of a variants (experiments, mods) system. Allows for dynamic flag evaluation based on conditions.
Clone or download
andybons Merge pull request #27 from Medium/andybons/races
Make a Registry safe to access from multiple goroutines.
Latest commit 2db3760 Dec 22, 2014



In web applications it is common to provide varying experiences to unique sets of users. A flexible design should allow implementations of common patterns in web development like:

  • A/B testing
  • Experimental features
  • Trusted tester groups
  • Gradual feature rollouts


Variants provide an expressive way to define and conditionally modify experimental features, which can also be forcefully adjusted (for development).

Note that the following README only provides a general overview of variants, and is language independent. Currently, there are ports written for Node.js and Go. See the implementation-specific READMEs for more information.

To conditionally gate certain features, they must be protected by variant flags. Variant flags are globally unique strings that can point to a language primitive, array or object. Most commonly, variant flags are simple boolean values so that the below code is possible:

if (variants.getFlagValue('enable_product_access')) {
  throw Error('Authenticated failed.')


  • Each service contains variants
  • Variants contain 0 or more conditions and 1 or more mods
  • Conditions evaluate the current request based on the condition type and values
  • Mods modify variant flags
  • Variant flags are checked in code to gate control flow


Variants are globally defined objects that may optionally modify values based on some conditions. All variants are evaluated on a per request basis, which means that they are scoped to request-based values such as: user ip, specific users, groups of users, query parameters, etc.

Variants must have an id and a list of conditions and mods. A variant must contain at least one mod to be valid.

variant: {
  required string id
  optional string conditional_operator
  optional condition[] conditions
  required mod[] mods


Conditions return true or false based on the current request object. If more than one condition is supplied, then the conditional_operator (either "OR" or "AND") must be supplied.

Below is a list of condition types:


User id is a condition that evaluates the given condition based on a list of usernames in the "values" field.


  "type": "USER_ID",
  "values": [


User id mods use a hashed value of the current user’s username mapped onto a range from 0-99. It allows the properties "range_start" and "range_end", which contain values between 0-99 and range_end must be greater than range_start.

By default, this uses the unique user id of an authenticated user. However, the "cookie_type" field can be set to "NSID" to refer to unauthenticated users.


  "type": "USER_ID_MOD",
  "values": [ 0, 9 ]

Note: This is useful for rolling out new features, such as to 1% -> 10% -> 50% -> 100% of users.


Random will randomly determine whether or not a given request is eligible for the variant.


  "type": "RANDOM",
  "value": 0.25


Mods are triggered when the conditions are met on the given variant. The format of a mod is simply a key and a value. The key must refer to a global identifier for the variant flag.

Full spec

Spec in pseudo-protobuf format:

message Variants {
  repeated Variant variants;

message Variant {

  enum Operator {
    AND, // "AND"
    OR   // "OR"

  // Unique identifier.
  required string id;

  // Readable description of the feature.
  optional string description;

  // Optional operator to evaluate the conditions.
  optional Operator conditional_operator;

  // List of conditions to evaluate.
  repeated Condition conditions;

  // List of mods to be triggered.
  repeated Mod mods;

message Condition {

  enum Type {

  // Type of condition.
  required Type type;

  // Single value.
  optional * value;

  // List of values.
  repeated * values;

message Mod {
  // Name of the variant flag to modify.
  required string flag;

  // Value to set.
  required * value;



Questions, comments, bug reports, and pull requests are all welcome. Submit them at the project on GitHub.

Bug reports that include steps-to-reproduce (including code) are the best. Even better, make them in the form of pull requests that update the test suite. Thanks!


David Byttow supported by The Obvious Corporation.


Copyright 2012 The Obvious Corporation.

Licensed under the Apache License, Version 2.0. See the top-level file LICENSE.txt and (