Flipping Strategies¶
Flipping strategies allow you to control when a feature is enabled based on dynamic conditions, rather than just a simple on/off toggle.
Overview¶
A FlippingStrategy is evaluated each time a feature is checked. This enables use cases like:
- Gradual rollouts (percentage-based)
- User-specific targeting
- A/B testing
- Time-based feature availability
Execution Context¶
Most strategies require runtime context (e.g., who is the current user?) to make decisions. You can pass this context using FlippingExecutionContext.
FF4K provides standard keys in ContextKeys for common parameters such as:
ContextKeys.USER_ID("userId"): Unique identifier for the user. Required for user-based strategies.ContextKeys.USER_NAME("userName"): User's display name.ContextKeys.REGION("region"): Geographic region (e.g., "EU", "US").ContextKeys.ENVIRONMENT("environment"): App environment (e.g., "prod", "staging").ContextKeys.CLIENT_HOSTNAME("clientHostname"): Client hostname making the request.ContextKeys.SERVER_HOSTNAME("serverHostname"): Server hostname handling the request.
val context = FlippingExecutionContext(
ContextKeys.USER_ID to "user-123",
ContextKeys.REGION to "EU"
)
ff4k.check("my-feature", context)
Constant Strategies¶
AlwaysTrueFlippingStrategy¶
Always returns true. Useful as a base case in composite strategies.
AlwaysFalseFlippingStrategy¶
Always returns false. Useful as a base case in composite strategies.
Percentage-Based Strategies¶
PonderationStrategy¶
Enables a feature based on a random percentage. Each evaluation is independent - the same user may get different results on subsequent calls.
feature("gradual-rollout") {
ponderationStrategy(0.25) // 25% chance of being enabled
}
// Or using integer percentage
feature("gradual-rollout") {
ponderationStrategy(25) // 25% chance
}
UserPonderationStrategy¶
Enables a feature for a consistent percentage of users. The same user always gets the same result (sticky sessions), making it ideal for A/B testing and gradual rollouts.
Requires ContextKeys.USER_ID in the execution context.
feature("beta-feature") {
userPonderationStrategy(0.10) // 10% of users
}
// Or using integer percentage
feature("beta-feature") {
userPonderationStrategy(10) // 10% of users
}
// Checking with user context
val context = FlippingExecutionContext(ContextKeys.USER_ID to currentUserId)
ff4k.check("beta-feature", context)
User-List Strategies¶
AllowListStrategy¶
Enables a feature only for specific users. All other users will have the feature disabled.
Requires ContextKeys.USER_ID in the execution context.
DenyListStrategy¶
Disables a feature for specific users. All other users will have the feature enabled.
Requires ContextKeys.USER_ID in the execution context.
Filter Strategies¶
ClientFilterStrategy¶
Enables a feature only for requests from specific client hostnames.
Requires ContextKeys.CLIENT_HOSTNAME in the execution context.
feature("internal-only") {
clientFilterStrategy {
+"client-a.internal.com"
+"client-b.internal.com"
}
}
// Checking with client context
val context = FlippingExecutionContext(ContextKeys.CLIENT_HOSTNAME to request.hostname)
ff4k.check("internal-only", context)
ServerFilterStrategy¶
Enables a feature only on specific server hostnames. Useful for canary deployments or testing features on specific server instances.
Requires ContextKeys.SERVER_HOSTNAME in the execution context.
feature("canary-feature") {
serverFilterStrategy {
+"server-1.prod.com"
+"server-2.prod.com"
}
}
// Checking with server context
val context = FlippingExecutionContext(ContextKeys.SERVER_HOSTNAME to System.getenv("HOSTNAME"))
ff4k.check("canary-feature", context)
RegionFilterStrategy¶
Enables a feature only for specific geographic regions.
Requires ContextKeys.REGION in the execution context.
feature("eu-only") {
regionStrategy {
+"eu-central-1"
+"eu-west-1"
}
}
// Checking with region context
val context = FlippingExecutionContext(ContextKeys.REGION to currentRegion)
ff4k.check("eu-only", context)
Time-Based Strategies¶
ReleaseDateStrategy¶
Enables a feature after a specified release date. The feature is disabled before the release date and enabled once the current time reaches or passes it.
Useful for scheduling feature launches without requiring a deployment.
// Using ISO-8601 string
feature("new-feature") {
releaseDateStrategy("2025-06-01T00:00:00Z")
}
// Using Instant
feature("new-feature") {
releaseDateStrategy(Instant.parse("2025-06-01T00:00:00Z"))
}
// Using LocalDateTime with timezone
feature("new-feature") {
releaseDateStrategy(
dateTime = LocalDateTime(2025, 6, 1, 9, 0),
timezone = TimeZone.of("America/New_York")
)
}
DateRangeStrategy¶
Enables a feature only within a specified time range. The feature is enabled when the current
time is at or after the start date and before the end date (i.e., [startDate, endDate)).
Useful for limited-time promotions, scheduled maintenance windows, or time-boxed experiments.
// Using ISO-8601 strings
feature("holiday-sale") {
dateRangeStrategy(
startDate = "2025-12-20T00:00:00Z",
endDate = "2025-12-26T00:00:00Z"
)
}
// Using Instant values
feature("maintenance-mode") {
dateRangeStrategy(
startDate = maintenanceStart,
endDate = maintenanceEnd
)
}
// Using LocalDateTime with timezone
feature("summer-promo") {
dateRangeStrategy(
startDate = LocalDateTime(2025, 6, 1, 0, 0),
endDate = LocalDateTime(2025, 8, 31, 23, 59),
timezone = TimeZone.of("Europe/London")
)
}
DailyHoursStrategy¶
Enables a feature only during specific hours of the day. The feature is enabled when the current
hour is within the specified range: [startHour, endHour) (start inclusive, end exclusive).
Useful for features that should only be available during business hours, off-peak times, or any recurring daily time window.
// Enable feature from 9 AM to 5 PM UTC
feature("business-hours") {
dailyHoursStrategy(
startHour = 9,
endHour = 17
)
}
// Enable feature during off-peak hours (10 PM to 00 AM) in a specific timezone
feature("off-peak-processing") {
dailyHoursStrategy(
startHour = 22,
endHour = 24,
timezone = TimeZone.of("America/New_York")
)
}
WeekdayStrategy¶
Enables a feature only on specific days of the week. The feature is enabled when the current day matches one of the allowed days.
Useful for features that should only be available on certain days, such as weekday-only features, weekend promotions, or scheduled maintenance windows.
// Enable feature on weekdays only
feature("weekday-feature") {
weekdayStrategy {
weekdays() // Monday through Friday
}
}
// Enable feature on weekends only
feature("weekend-promo") {
weekdayStrategy {
weekends() // Saturday and Sunday
}
}
// Enable feature on specific days
feature("tuesday-thursday") {
weekdayStrategy(TimeZone.of("Europe/London")) {
+DayOfWeek.TUESDAY
+DayOfWeek.THURSDAY
}
}
// Enable feature every day (useful when combined with other strategies)
feature("all-week") {
weekdayStrategy {
allDays()
}
}
Composite Strategies¶
Combine multiple strategies using logical operators.
AndStrategy¶
All strategies must evaluate to true.
OrStrategy¶
At least one strategy must evaluate to true.
NotStrategy¶
Inverts the result of a strategy.
Combining Strategies¶
You can chain multiple operators to create complex conditions:
For creating custom strategies, see Extending FF4K.