Coming soon! A Pro version of the Flipper gem for entirely local installations.

Get Updates

Documentation

Expressions

Enable features by defining rules that evaluate against properties of an actor and a feature context.

NOTE
Expressions are an experimental feature and are subject to change. Please provide feedback if you use them.

Flipper Expressions are a powerful new way to enable features that support complex logic. They are language-agnostic and are stored in JSON, so they can sync between your application and Flipper Cloud.

Enabling an expression

The simplest expression is a comparison of a property on the actor to a given value. For example, if we have a User model with an age property, we can enable a feature for users of a given age:

must_be_21 = Flipper.property(:age).gte(21)
Flipper.enable :night_club, must_be_21

Now we can test it for two actors of different ages:

# Under age
Flipper.enabled? :night_club, User.new(age: 18) #=> false

# Of age
Flipper.enabled? :night_club, User.new(age: 21) #=> true

The Property expression extracts a property from the actor (by calling #flipper_properties on it), and in this case we use the GreaterThanOrEqualTo (aliased to gte) expression to compares it to the constant 21.

You can compare any two values using eq, gt, lt, gte, lte, or ne.

Combining expressions

What if you want to enable a feature for users who are over 21 and have either paid or are a VIP? No problem, you can group expressions together using all and any, and even nest groups inside each other:

over_21 = Flipper.property(:age).gte(21)
paid = Flipper.property(:paid).eq(true)
vip = Flipper.property(:vip).eq(true)

Flipper.enable :night_club, Flipper.all(over_21, Flipper.any(paid, vip))

Now we can test it for three different actors:

# Unpaid
Flipper.enabled? :night_club, User.new(2, age: 18, paid: false) #=> false
# Paid
Flipper.enabled? :night_club, User.new(1, age: 18, paid: true) #=> true
# Unpaid, but VIP
Flipper.enabled? :night_club, User.new(3, age: 18, paid: false, vip: true) #=> true

These groups can take any number of sub-expressions, and can be nested in any number of ways to create complex rules.

Time-based expressions

You can enable features based on time using the Now and Time expressions. These work without an actor, so no flipper_properties are required.

Scheduled enablement

Enable a feature starting at a specific time:

expression = Flipper.now.gte(Flipper.time("2026-03-01T00:00:00Z"))
Flipper.enable :new_feature, expression

Expiring feature

Enable a feature until a specific time:

expression = Flipper.now.lt(Flipper.time("2026-04-01T00:00:00Z"))
Flipper.enable :promo_banner, expression

Time window

Enable a feature during a specific time range:

start_time = "2026-03-01T00:00:00Z"
end_time = "2026-04-01T00:00:00Z"

expression = Flipper.all(
  Flipper.now.gte(Flipper.time(start_time)),
  Flipper.now.lt(Flipper.time(end_time))
)
Flipper.enable :spring_sale, expression

Combined with actor properties

Combine time-based expressions with property checks:

expression = Flipper.all(
  Flipper.property(:plan).eq("basic"),
  Flipper.now.gte(Flipper.time("2026-03-01T00:00:00Z"))
)
Flipper.enable :new_feature, expression

Expression types

  • Flipper.now — Returns the current time in UTC. Takes no arguments.
  • Flipper.time(value) — Parses a time value. Accepts ISO 8601 strings (e.g. "2026-03-01T00:00:00Z") or epoch timestamps (e.g. 1708300800). Always returns UTC.

Feature dependencies

You can make a feature depend on another feature using Flipper.feature_enabled and Flipper.feature_disabled. This allows you to create feature flag dependencies without custom code.

Enable only if another feature is on

Flipper.enable(:search_beta)
Flipper.enable :search_v2, Flipper.feature_enabled(:search_beta)

The actor is passed through, so if the referenced feature is enabled for specific actors, the dependent feature respects that:

Flipper.enable_actor(:search_beta, user)
Flipper.enable :search_v2, Flipper.feature_enabled(:search_beta)

Flipper.enabled?(:search_v2, user)        #=> true
Flipper.enabled?(:search_v2, other_user)  #=> false

Enable only if another feature is off

Flipper.enable :new_checkout, Flipper.feature_disabled(:old_checkout)

Combined with other expressions

Flipper.enable :advanced_search, Flipper.all(
  Flipper.feature_enabled(:basic_search),
  Flipper.property(:plan).eq("premium")
)

Circular dependencies (A depends on B, B depends on A) are detected automatically and return false.

flipper_properties

To use expressions, you'll need to ensure that actors respond to flipper_properties and return a hash of properties that you want to use in expressions. This is defined on ActiveRecord models by default. If you want to use expressions with a different model, you can define a method that returns a hash of properties:

class User < Struct.new(:id, :flipper_properties)
  include Flipper::Identifier
end

basic_user = User.new(1, {"plan" => "basic", "age" => 30})
premium_user = User.new(2, {"plan" => "premium", "age" => 40})

To learn more, check out the plethora of code samples in examples/expressions.rb.

Ready to try it out?

Get audit history, rollbacks, advanced permissions, analytics, and all of your projects in one place.


Prefer our Cloudless option?

You can choose from several tiers to sponsor Flipper on GitHub and get some great benefits!

The Friday Deploy

Get updates for all things Flipper—open source and cloud.

Have questions? Need help?

Email us any time or head on over to our documentation or status page for the latest on the app or API.

Ready to take Flipper for a swim?

No credit card required. 14-day free trial. And customer support directly from the developers.