Swiftpack.co - Package - unsignedapps/Vexil


Vexil (named for Vexillology) is a Swift package for managing feature flags
(also called feature toggles) in a flexible, multi-provider way.


  • 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


In addition to this README, which covers basic usage and installation, you can find more documentation:


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.


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.


We welcome all contributions! Please read the Contribution Guide for details on how to get started.


Vexil is available under the MIT license. See the LICENSE file for more info.


Stars: 69


Used By

Total: 0


Release 1.2.1 - 2020-09-26 11: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-14 15: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-24 07:46:56

What’s Changed

  • Provided explicit -static and -dynamic versions of the products (@bok-)

Release 1.1 – Flag Publishing - 2020-08-17 12: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-02 09:31:22

What’s Changed

We've finally reached the first proper release! πŸŽ‰

πŸš€ Features

  • Removed the requirement that FlagValues also conform to Codable. @bok- (#37)
  • Improved Unit Tests @bok- (#36)

πŸ“š Documentation Changes

  • Updated documentation and templates @bok- (#38)

Release 0.2.9 – Bug Fixes 🐞 - 2020-07-31 06: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-30 08: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-30 03:57:07

What’s Changed

πŸš€ Features

  • Added a BoxedValueType to the FlagValue protocol to provide simplified type hints to FlagValueSource implementations @bok- (#28)

Release 0.2.2 – Snapshots and Optionals - 2020-07-21 01: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-16 04: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 the FlagDetailView @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-15 11: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 and Picker 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-13 05:57:09

What's Changed

πŸ› Bug Fixes

  • Fixed display of digits in Vexillographer property display names @bok- (#15)

Initial Pre-Release - 2020-07-13 05: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)