Flipper Cloud

Flipper Cloud Documentation

What is this?

Flipper Cloud is a platform for simple, beautiful and performant feature flags for Ruby.

We make it easy to...

  • Manage all your projects in one place. Rather than having feature flags setup in separate or unique ways for each application or micro-service, we can centralize feature flag control, access and auditing for your entire organization.
  • Give non-technical staff the power to release code. Engineers setup the conditionals in the code, but anyone can enable or disable them using targeting as wide as a group or % of users to as narrow as a single user or random moment in time.
  • Get code into production faster. Once a feature flag is in place and protecting your new code, you can ship the new code to production and avoid long lived version control branches (and the hassle that comes with keeping them up to date and merging/deploying them safely).
  • Safely isolate new and existing code. Turning off a feature flag is always faster than a rollback. Similarly, sometimes you just want to turn something non-critical off and go back to bed. We make it a single button click (and include an audit log of every change).
  • Slowly rollout new features. By enabling a feature for a small percentage of users and slowly increasing, you can gain confidence in a new application feature and avoid a thundering herd of users eager to check it out.

Who are you?

Flipper Cloud is built with a lot of ❤️ in South Bend, Indiana by Fewer & Faster — owned by John Nunemaker & Steve Smith. Steve leans toward the form (design) and John toward the function (code). That said, our venn diagram of skills overlaps quite a bit.

We owned a company together a decade ago where we were consultants and built a few products — including Speaker Deck. In 2011, we were acquired by GitHub. We worked there for many years — while it grew from 50 to thousands of employees.

While at GitHub we maintained their open source setup of Flipper, which served billions of feature checks a day and was one of the most stable pieces of infrastructure.

Seeing how Flipper changed the way GitHub released software was inspiring. Why not re-build it so everyone can partake? Thus Flipper Cloud was born.

In 2018, we created a new company, Fewer & Faster, to acquire Speaker Deck back from GitHub and to build Flipper Cloud.

How does it work?

We have a beautiful, web interface for managing your organizations, projects, environments and features. Additionally, we expose a simple HTTP API along with a client library that takes only a few minutes to integrate into your application.

When you create a project, it comes preloaded with a production environment and a personal environment for each developer to get you up and running quickly. But we support as many other environments as necessary (e.g. staging, smoke, Heroku review app, or whatever you can dream up).

Just show me the code! Ok, here is a quick example:

Basic Setup
require "flipper/cloud" Flipper.configure do |config| config.default { Flipper::Cloud.new("<your-token-here>") } end if Flipper.enabled?(:billing) # get paid else # wish you were getting paid end

For more details and best practices, read the getting started guide below or check out our Flipper Cloud rails demo app.

Organizations

Organizations allow you to group projects for permissions and billing purposes. You can belong to one or more organizations. Each organization can have as many projects and members as necessary. Organization members are automatically granted access to all projects owned by the organization.

Projects

Projects allow you to manage many different applications and services under one organization. Each project has its own environments and features. All members of the owning organization are automatically granted access to the project. Additionally, you can grant access for people directly to one or more projects.

Environments

Environments allow you to model your development lifecycle and vary feature enablement depending on where the code is executed (e.g. from local development to staging to production).

Production and personal environments (one for each organization member and project collaborator) are automatically created for each project, but you are free to add any others as needed (e.g. staging, etc.).

All feature enablements are scoped to environment, but by default mirror production. This means that if a feature is enabled in production, it is enabled in all environments, unless that environment has explicitly overridden it (e.g. disabled in production, but enabled in local development for engineers).

API Tokens

Each environment can have one or more API tokens as well, allowing for rotation without impacting currently in use tokens. You can generate a new token, update your application configuration to the new token, and archive the old token to rotate the token.

The only purpose of the API is to keep your application in sync with changes in Flipper Cloud. You can poll the API to stay in sync or, even better, use webhooks for faster updates (than polling) and more isolation from Flipper Cloud.

Webhooks

Webhooks keep your application in sync with Cloud without polling. Each environment can have multiple webhooks. Anytime something changes for that environment, we'll send a webhook request to your app to tell it to sync with Cloud.

We recommend this route for production. But you can also use it for staging or other environments that are exposed to the internet. Using webhooks keeps your features in sync without polling Flipper Cloud, which means all feature check reads are local to your application and blazing fast.

Features

Features are the heart of Flipper Cloud. They allow you to control code execution based on a few different types of enablement.

1. Boolean

All on or all off. Think top level things like :stats, :search, :logging, etc. Also, an easy way to release a new feature, as once a feature is boolean enabled it is on for every situation.

Boolean Example
user = User.find(...) Flipper.enabled?(:search) # false Flipper.enabled?(:search, user) # false Flipper.enable(:search) Flipper.enabled?(:search) # true Flipper.enabled?(:search, user) # true

2. Group

Turn on feature based on the return value of block. Super flexible way to turn on a feature for multiple things (users, people, accounts, etc.) as long as the thing returns true when passed to the block.

Group Example
user = User.find(...) # user who returns false for admin? method admin = User.find(...) # user who returns true for admin? method # Define the block that will return true or false based on actor. Registers a # group named admins which saves the block to be called later. Flipper.register(:admins) do |actor, context| actor.respond_to?(:admin?) && actor.admin? end Flipper.enabled?(:documentation, user) # false Flipper.enabled?(:documentation, admin) # false # Enable the block named admins which means future enabled? checks will see if # the passing the actor to the block returns true. Flipper.enable_group(:documentation, :admins) # When user is passed to enabled?, Flipper knows that the admins group is # enabled. It executes the registered block above, yielding user. user responds # to admin?, but admin? returns false, which means the feature will not be # enabled for the user (true && false == false). Flipper.enabled?(:documentation, user) # false # Same as the previous check, but this time admin? returns true for the user # which means the feature will be enabled (true && true == true). Flipper.enabled?(:documentation, admin) # true

There is no requirement that the thing yielded to the block be a user model or whatever. It can be anything you want, therefore it is a good idea to check that the thing passed into the group block actually responds to what you are trying to do in the register proc. This is why the :admin group above uses respond_to?.

3. Actor

Turn feature on for individual thing. Think enable feature for someone to test or for a buddy. The only requirement for an individual actor is that it must respond to flipper_id.

Actor Example
user = User.find(...) other_user = User.find(...) Flipper.enabled?(:verbose_logging) # false Flipper.enabled?(:verbose_logging, user) # false Flipper.enable_actor(:verbose_logging, user) Flipper.enabled?(:verbose_logging) # false Flipper.enabled?(:verbose_logging, user) # true Flipper.enabled?(:verbose_logging, other_user) # false

The key is to make sure you do not enable two different types of objects for the same feature. Imagine that user has a flipper_id of 6 and group has a flipper_id of 6. Enabling search for user would automatically enable it for group, as they both have a flipper_id of 6.

The one exception to this rule is if you have globally unique flipper_ids, such as UUIDs. If your flipper_ids are unique globally in your entire system, enabling two different types should be safe. Another way around this is to prefix the flipper_id with the class name like this:

class User def flipper_id "User;#{id}" end end class Group def flipper_id "Group;#{id}" end end

4. Percentage of Actors

Turn this on for a percentage of actors (think user, member, account, group, whatever). Consistently on or off for this user as long as percentage increases. Think slow rollout of a new feature to a percentage of things.

Percentage of Actors Example
user = User.find(...) # responds to flipper_id method call Flipper.enable_percentage_of_actors(:new_design, 25) # returns true or false consistently for the same enabled percentage and actor Flipper.enabled?(:new_design, user)

Percentage of actors also takes into account the feature name to ensure that the same actors are not granted access first to every feature.

Note: 100% of actors will not return true if no actor is provided.

user = User.find(...) # responds to flipper_id method call # turn on for all actors Flipper.enable_percentage_of_actors(:new_design, 100) # true because 100% and actor is passed Flipper.enabled?(:new_design, user) # true # false because no actor provided Flipper.enabled?(:new_design) # => false Flipper.enabled?(:new_design, nil) # => false

5. Percentage of Time

Turn this on for a percentage of time. Think load testing new features behind the scenes and such.

Percentage of Time Example
user = User.find(...) Flipper.enable_percentage_of_time(:dark_ship_new_feature, 25) # returns true for ~25% of the enabled? calls irregardless of the actor provided Flipper.enabled?(:dark_ship_new_feature) Flipper.enabled?(:dark_ship_new_feature, user)

Percentage of time is not a good idea for enabling new features in a UI. Most often you'll use percentage of actors, but there are definitely times when I have found percentage of time to be very useful.

Audit history

One of the handiest upgrades from open source Flipper is Flipper Cloud's audit history. We keep track of who changed a feature, when they changed it and what changes were made.

We even go one step farther and allow you to view or rollback to any point in time. Accidentally enable a feature that was previously conditionally enabled for 3 actors and 2 groups? No problem. Just rollback to where things were good and get back to work.

Getting Started

Setting up Flipper takes only a few minutes. Follow the guide below or let us know if you would prefer to have us do it for you.

For the moment, Flipper Cloud only supports ruby applications. If there is another language you would like to see support for, we would love to know.

Ruby on Rails

In addition to the steps outlined below, we have a fully functional example Rails application for you to peruse.

Step 1. Add Flipper to your Gemfile

Gemfile
# Required: This is what talks to flippercloud.io on your behalf. gem "flipper-cloud", "~> 0.20.3" # Optional: This can be any other Flipper adapter (e.g. redis, mongo, etc.). It # defaults to in memory, but we highly recommend something persistent, like # the active record adapter. gem "flipper-active_record", "~> 0.20.3"

Run bundle to install.

$ bundle

If you're using the ActiveRecord adapter, you'll also need to generate the migrations and run them.

$ bin/rails g flipper:active_record $ bin/rails db:migrate

Step 2. Configure Flipper with ENV variables (recommended):

Create a new file config/initializers/flipper.rb with the following content:

config/initializers/flipper.rb
require "flipper/cloud" require "flipper/adapters/active_record" Flipper.configure do |config| config.default do Flipper::Cloud.new do |cloud| cloud.local_adapter = Flipper::Adapters::ActiveRecord.new end end end Rails.configuration.middleware.use Flipper::Middleware::Memoizer, preload_all: true

Based on that configuration, you'll need the following ENV variables:

# required FLIPPER_CLOUD_TOKEN=<your-token-here> # optional, but recommended for production environment # see webhooks below for more FLIPPER_CLOUD_SYNC_METHOD=webhook FLIPPER_CLOUD_SYNC_SECRET=<webhook-secret>

Or, Configure Flipper in Ruby:

If your application is not configured through ENV variables, you can substitute the token and secret in the code below however you like.

Flipper.configure do |config| config.default do Flipper::Cloud.new("<your-token-here>") do |cloud| cloud.sync_method = Rails.env.production? ? :webhook : :poll cloud.sync_secret = "<webhook-secret>" cloud.local_adapter = Flipper::Adapters::ActiveRecord.new end end end

Step 3. Setup Webhooks for Production

The instructions above are great for your laptop and even staging environments, but for production we recommend syncing using webhooks.

Using webhooks means that your app is entirely disconnected from Cloud for reads (e.g. enabled?). Your app will only communicate with Cloud for writes (e.g. enable and disable). This ensures that your availability is not tied to ours, which is always a good practice for external services.

3a. Create a Webhook in Cloud

Add a new production webhook in Cloud. The webhook URL can be anything, but we recommend https://yourapplication.com/_flipper/webhooks.

Once you create the webhook, you'll be taken to a page where you can get the webhook's secret. FLIPPER_CLOUD_SYNC_SECRET or cloud.sync_secret should be set to this value.

3b. Configure Your App to Receive Webhooks

Next, mount Flipper::Cloud.app in config/routes.rb.

config/routes.rb
SpeakerDeck::Application.routes.draw do # This is the key line. mount Flipper::Cloud.app, at: "_flipper" end

This mounted Rack app will receive webhooks for your app, verify that they are from Cloud, and synchronize your local adapter with Cloud.

Done

That's it. For a dozen lines of code and a couple of clicks you get the full power of feature toggles with little to no performance impact.

Need Help?

We would be delighted to answer any questions or even setup a pairing session to help you get your application setup correctly. Shoot an email to support@flippercloud.io.

Open Source Flipper Migration to Flipper Cloud

If you are already using the open source version of Flipper, migration to Flipper Cloud is easy since Flipper supports syncing between adapters.

# create an instance of flipper with whatever adapter you are using current_flipper = Flipper.new(Flipper::Adapters::Memory.new) # makes cloud identical to memory flipper # note: this will wipe out whatever is in cloud Flipper::Cloud.new("<your-token-here>").import(current_flipper)