📚 Documentation
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
💡 Why Featury?
- 🎯 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
🚀 Quick Start
Installation
Add Featury to your Gemfile:
gem "featury"ApplicationFeature
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
endFeature Definitions
Define 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
endUsage
# 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 # => true🤝 Contributing
This 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.
🙏 Acknowledgments
Featury is built and maintained by amazing contributors.
📄 License
Featury is available as open source under the terms of the MIT License.