Vexil (named for Vexillology) is a Swift package for managing feature flags
(also called feature toggles) in a flexible, multi-provider way.
Features
- Define your flags in a structured tree
- Extensible to support any backend flag storage or platform
- Take and apply snapshots of flag states
- Get real-time flag updates using Combine
- Vexillographer: A simple SwiftUI interface for editing flags
Documentation
In addition to this README, which covers basic usage and installation, you can find more documentation:
- On our documentation website: https://unsignedapps.github.io/Vexil/
- Detailed documentation and guides in the Documentation subdirectory
Usage
Defining Flags
If you've ever used swift-argument-parser defining flags in Vexil will be a familiar experience.
Vexil supports a tree of flags, so we need a structure to hold them:
import Vexil
struct LoginFlags: FlagContainer {
@Flag("Enables the forgot password button on the login screen and associated flows")
var forgotPassword: Bool
}
Side Note: Vexil requires descriptions for all of its flags and flag groups. This is used by Vexillographer for providing context for the flags you are enabling/disabling in the UI, but it also provides context for future developers (especially yourself in 12 months time) as to what flags mean and what their intended use is.
See the full documentation for how to define flags to read more
Checking flags
To check your flags, you need to run them up a Flag Pole:
import Vexil
let flagPole = FlagPole(hoist: AppFlags.self)
// should we show the change password screen?
if flagPole.profile.password.changePassword {
// ...
}
Mutating flags
By default access to flags on the FlagPole is immutable from your source code. This is a deliberate design decision: flags should not be easily mutatable from your app as it can lead to mistakes (eg. flag = true
instead of flag == true
).
That said, it is still very easy to mutate any flags if you need to using a snapshot:
import Vexil
let flagPole = FlagPole(hoist: AppFlags.self)
var snapshot = flagPole.emptySnapshot()
snapshot.profile.password.changePassword = true
// insert it at the top of the hierarchy
flagPole.insert(snapshot: snapshot, at: 0)
For more info see Snapshots.
Flag Value Sources
The Vexil FlagPole
supports multiple backend flag sources, and ships with the following sources built-in:
Name | Description |
---|---|
UserDefaults |
Any UserDefaults instance automatically conforms to FlagValueSource |
Snapshot |
All snapshots taken of a FlagPole can be used as a source. |
See the full documentation on Flag Value Sources for more on working with sources and how to define your own.
Snapshots
Vexil provides a mechanism to mutate, save, load and apply snapshots of flag states and values.
Important: Snapshots only reflect values and states that have been mutated. That is, a snapshot is only applied to values that have been explicitly set within it. Any values that have not been set will defer to the next source in the list, or the default value. The exception is when you take a full snapshot of a FlagPole, which captures the value of every flag.
Snapshots are implemented as a FlagValueSource
, so you can easily apply multiple snapshots in a prioritised order.
Snapshots can do a lot. See our Snapshots Guide for more.
Creating snapshots
You can manually create snapshots and specify which flags are affected:
import Vexil
// create an empty snapshot
var snapshot = flagPole.emptySnapshot()
// update some values and states
snapshot.login.forgotPassword = false
snapshot.profile.password = false
// apply that snapshot - only the two values above will change
flagPole.insert(snapshot: snapshot, at: 0)
You can also take a snapshot of the current state of your FlagPole:
import Vexil
let flagPole = FlagPole(hoist: AppFlags.self)
// snapshot the current state - this will get the state of *all* flags
let snapshot = flagPole.snapshot()
// save them, mutate them, whatever you like
// ...
Installing Vexil
To use Vexil in your project add it as a dependency in a Swift Package, add it to your Package.swift
:
dependencies: [
.package(url: "https://github.com/unsignedapps/Vexil.git", from: "1.0.0")
]
And add it as a dependency of your target:
targets: [
.target(name: "MyTarget", dependencies: [
.product(name: "Vexil", package: "Vexil")
])
]
In Xcode 11+
To use Vexil in Xcode 11 or higher, navigate to the File menu and choose Swift Packages -> Add Package Dependency..., then enter the repository URL and version details for the release as desired.
Vexillographer: A SwiftUI Flag Manipulation Tool
The second library product of Vexil is Vexillographer, a small SwiftUI tool for displaying and manipulating flags.



Read more about Vexillographer.
Contributing
We welcome all contributions! Please read the Contribution Guide for details on how to get started.
License
Vexil is available under the MIT license. See the LICENSE file for more info.
Github
link |
Stars: 72 |
You may find interesting
Releases
Release 1.3.1 - 2020-11-25T11:35:50
Whatβs Changed
π Features
- Improve section-styled FlagGroup display on macOS @RodBrown1988 (#69)
π Bug Fixes
- Fixed bug introduced in #67 that caused the description and flags to run together on iOS @RodBrown1988 (#69)
- Fixed bug introduced in #67 that caused the navigation title to be wrong on iOS when using
.section
flag groups @RodBrown1988 (#69)
Release 1.3.0: Back to the Mac π₯οΈ - 2020-11-23T12:47:49
π Highlights
Proper support for macOS (11+) in Vexillographer, with huge thanks to @RodBrown1988
π Features
- Add Mac flag detail view with context menu @RodBrown1988 (#66)
- Improve FlagGroupView on the Mac @RodBrown1988 (#65)
- Improve "Clear Flag" button with animation instead of removal @RodBrown1988 (#64)
- Improve Detail Button behaviour in iOS forms @RodBrown1988 (#62)
- Vexillographer Mac UI Uplift @RodBrown1988 (#61)
π Bug Fixes
- Fixed issue on iOS where FlagGroup's displayed as sections were being nested inside SwiftUI Section views, causing rendering issues @bok- (#67)
π§° Maintenance
- Added support for additional combinations of Xcode (12.3, 12.2, 12.1, 12.0, 11.7) and Swift (5.2, 5.3, 5.3.1) as well as macOS 11 (Xcode 12.3, 12.2, 11.7) in CI @bok- (#63 and #68)
- XCFrameworks attached to this release are now built with swift-create-xcframework 1.3.0 and so include debug symbols (dSYM and bcsymbolmap as appropriate)
Release 1.2.2 - 2020-10-04T06:18:10
Whatβs Changed
π Features
- Highlighted flags in Vexillographer that have overridden values. @bok- (#59)
- Added support for displaying FlagGroups as Sections in Vexillographer @bok- (#58)
Release 1.2.1 - 2020-09-26T11:57:24
Whatβs Changed
π Features
- Added support for Optional and RawRepresentable values to Vexillographer @bok- (#56)
π Bug Fixes
- Fixed case where Flag Values that were Bool? or RawRepresentable where RawValue == Bool would fail to decode from UserDefaults @bok- (#57)
- Hide flags from Vexillographer that aren't supported for editing @bok- (#55)
Release 1.2.0 - 2020-09-14T15:01:05
Whatβs Changed
π Features
- Added NSUbiquitousKeyValueStore support @bok- (#51)
π Bug Fixes
- The UserDefaults FlagValueSource now emits when the application re-opens @bok- (#53)
- Removed the explicit products as they seem to crash Xcode 12 @bok- (#50)
π§° Maintenance
- Added additional unit test CI jobs for all supported platforms @bok- (#54)
- Updated support for Swift 5.3, iOS 14 and macOS 11 @bok- (#52)
Release 1.1.1 - 2020-08-24T07:46:56
Whatβs Changed
- Provided explicit
-static
and-dynamic
versions of the products (@bok-)
Release 1.1 β Flag Publishing - 2020-08-17T12:44:44
Whatβs Changed
π Features
- Added a simple
FlagValueDictionary
source @bok- (#44) - Added a
Flag.publisher
property @bok- (#41)
π Documentation Changes
- Added generated API documentation @bok- (#40)
Initial Release β 1.0.0 π - 2020-08-02T09:31:22
Whatβs Changed
We've finally reached the first proper release! π
π Features
- Removed the requirement that
FlagValue
s also conform toCodable
. @bok- (#37) - Improved Unit Tests @bok- (#36)
π Documentation Changes
- Updated documentation and templates @bok- (#38)
Release 0.2.9 β Bug Fixes π - 2020-07-31T06:17:01
Whatβs Changed
π Bug Fixes
- Fixed crash when the FlagViewSource list changed while the FlagDetailView was open @bok- (#35)
- Fixed scenario where flags could not be updated in Vexillographer @bok- (#33)
- Fixed recent regression where Snapshots were not being published at all @bok- (#32)
Release 0.2.6 β Flag Keys π and Bug Fixes π - 2020-07-30T08:08:56
Whatβs Changed
π Features
- Added the flag key to the FlagDetailView @bok- (#31)
π Bug Fixes
- Don't setup Snapshot Publishing before publishing is required @bok- (#29)
- Fixed infinite loop when setting up snapshot publishing @bok- (#30)
Release 0.2.3 β Type hints for FlagValueSources π΅οΈββοΈ - 2020-07-30T03:57:07
Whatβs Changed
π Features
- Added a
BoxedValueType
to theFlagValue
protocol to provide simplified type hints toFlagValueSource
implementations @bok- (#28)
Release 0.2.2 β Snapshots and Optionals - 2020-07-21T01:29:48
Whatβs Changed
π Features
- Added support for
Optional
Flag Values @bok- (#27)
π Bug Fixes
- Fixed forced unwrap error when accessing/setting values on a Snapshot @bok- (#26)
Patch Release 0.2.1 - 2020-07-16T04:14:15
Whatβs Changed
π Features
- Identified the current source (if known) in the Vexillographer hierarchy display @bok- (#24)
- Respect
FlagDisplayView
when displaying flag values in theFlagDetailView
@bok- (#22) - Removed the explicit
Form
used in the Vexillographer view as this limits how the view can be consumed @bok- (#23)
π§° Maintenance
- Opted out of the SwiftLint Action's changed files detection @bok- (#25)
Feature Complete: v0.2.0 - 2020-07-15T11:32:07
Whatβs Changed
This release includes the final features earmarked for Vexil 1.0 and can be considered feature complete. There will be a couple of subsequent releases for bug fixes and getting documentation, unit tests and GitHub workflows in order prior to 1.0.
π Features
- Added support for
TextField
andPicker
flag editing controls @bok- (#21) - Packaged name and description into a
FlagInfo
type and a .hidden option for hiding items from Vexillographer @bok- (#20) - Added optional
FlagValueDisplay
protocol to customise the display of flag values @bok- (#19) - Refactored
FlagValue
encoding and decoding @bok- (#16)
π Bug Fixes
- Fixed incorrect unboxing of Int values from
UserDefaults
@bok- (#18)
Pre-Release v0.1.1 - 2020-07-13T05:57:09
What's Changed
π Bug Fixes
- Fixed display of digits in Vexillographer property display names @bok- (#15)
Initial Pre-Release - 2020-07-13T05:06:11
Whatβs Changed
π Features
- Vexillographer @bok- (#12)
- Added support for custom display names @bok- (#14)
- Added Custom Fully Qualified Key Paths @bok- (#13)
- Simplified Snapshots @bok- (#9)
π Bug Fixes
- Miscellaneous Fixes @bok- (#11)
- Disable Combine-based Publishing on Linux @bok- (#4)
π Documentation Changes
- Added initial Vexil logo @bok- (#6)
π§° Maintenance
- Integrate with SonarCloud for code quality scans @bok- (#5)
- Disable the unit tests from running unless we change a relevant file @bok- (#7)
- Setup GitHub Actions for CI @bok- (#3)