See featury.servactory.com for comprehensive guides and API documentation.
Complete documentation is also available in the docs directory:
- Getting Started
- Features
- Groups
- Actions
- Resources
- Conditions
- Working with Features
- Info and Introspection
- Integration
- Examples
- Best Practices
- π― Unified Feature Management β Group and manage multiple feature flags through a single interface with automatic prefix handling
- π Flexible Integration β Works with any backend: Flipper, Redis, databases, HTTP APIs, or custom solutions
- ποΈ Powerful Organization β Organize features with prefixes, groups, and nested hierarchies for scalable feature management
- π Rich Introspection β Full visibility into features, actions, and resources through the comprehensive info API
- πͺ Lifecycle Hooks β Before/after callbacks for actions with customizable scope and full context access
- π‘οΈ Type-Safe Resources β Built on Servactory for robust resource validation, type checking, and automatic coercion
Add Featury to your Gemfile:
gem "featury"Create a base class that defines how features interact with your feature flag system:
class ApplicationFeature < Featury::Base
action :enabled?, web: :enabled? do |features:, **options|
features.all? { |feature| Flipper.enabled?(feature, *options.values) }
end
action :disabled?, web: :regular do |features:, **options|
features.any? { |feature| !Flipper.enabled?(feature, *options.values) }
end
action :enable, web: :enable do |features:, **options|
features.all? { |feature| Flipper.enable(feature, *options.values) }
end
action :disable, web: :disable do |features:, **options|
features.all? { |feature| Flipper.disable(feature, *options.values) }
end
action :add, web: :regular do |features:, **options|
features.all? { |feature| Flipper.add(feature, *options.values) }
end
before do |action:, features:|
Slack::API::Notify.call!(action:, features:)
end
after :enabled?, :disabled? do |action:, features:|
Slack::API::Notify.call!(action:, features:)
end
endDefine features with prefixes, resources, conditions, and groups:
class User::OnboardingFeature < ApplicationFeature
prefix :user_onboarding
resource :user, type: User
condition ->(resources:) { resources.user.onboarding_awaiting? }
feature :passage, description: "User onboarding passage feature" # => :user_onboarding_passage
group BillingFeature, description: "Billing functionality group"
group PaymentSystemFeature, description: "Payment system functionality group"
endclass BillingFeature < ApplicationFeature
prefix :billing
feature :api, description: "Billing API feature" # => :billing_api
feature :webhooks, description: "Billing webhooks feature" # => :billing_webhooks
endclass PaymentSystemFeature < ApplicationFeature
prefix :payment_system
feature :api, description: "Payment system API feature" # => :payment_system_api
feature :webhooks, description: "Payment system webhooks feature" # => :payment_system_webhooks
end# Direct method calls
User::OnboardingFeature.enabled?(user:) # => true
User::OnboardingFeature.enable(user:) # => true
User::OnboardingFeature.disable(user:) # => true
# Using .with() method
feature = User::OnboardingFeature.with(user:)
feature.enabled? # => true
feature.enable # => true
feature.disable # => trueThis project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the Contributor Covenant code of conduct. We recommend reading the contributing guide as well.
Featury is built and maintained by amazing contributors.
Featury is available as open source under the terms of the MIT License.