{"id":13995325,"url":"https://github.com/unsignedapps/Vexil","last_synced_at":"2025-07-22T21:32:40.451Z","repository":{"id":45435434,"uuid":"266929372","full_name":"unsignedapps/Vexil","owner":"unsignedapps","description":"Vexil (named for Vexillology) is a Swift package for managing feature flags (also called feature toggles) in a flexible, multi-provider way.","archived":false,"fork":false,"pushed_at":"2024-08-02T13:16:51.000Z","size":3058,"stargazers_count":118,"open_issues_count":12,"forks_count":12,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-17T17:39:29.204Z","etag":null,"topics":["feature-flags","feature-toggles","swift"],"latest_commit_sha":null,"homepage":"https://vexil.unsignedapps.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unsignedapps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-26T02:49:11.000Z","updated_at":"2024-11-14T00:22:38.000Z","dependencies_parsed_at":"2023-12-31T11:24:04.425Z","dependency_job_id":"ed77ca64-f61e-4520-a570-a7bf7fd9caf8","html_url":"https://github.com/unsignedapps/Vexil","commit_stats":{"total_commits":251,"total_committers":5,"mean_commits":50.2,"dds":0.3266932270916335,"last_synced_commit":"2b23383d9df0be5257bc30e09c1393c4bc58b44c"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsignedapps%2FVexil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsignedapps%2FVexil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsignedapps%2FVexil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unsignedapps%2FVexil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unsignedapps","download_url":"https://codeload.github.com/unsignedapps/Vexil/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227177902,"owners_count":17743197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["feature-flags","feature-toggles","swift"],"created_at":"2024-08-09T14:03:20.996Z","updated_at":"2024-11-29T17:31:29.595Z","avatar_url":"https://github.com/unsignedapps.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"![Vexil][vexil-logo]\n\n\u003cp align=\"center\"\u003eVexil (named for \u003ca href=\"https://en.wikipedia.org/wiki/Vexillology\"\u003eVexillology\u003c/a\u003e) is a Swift package for managing feature flags \u003cbr /\u003e(also called feature toggles) in a flexible, multi-provider way.\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://sonarcloud.io/dashboard?id=unsignedapps_Vexil\"\u003e\u003cimg src=\"https://sonarcloud.io/api/project_badges/measure?project=unsignedapps_Vexil\u0026metric=alert_status\"\u003e\u003c/a\u003e\n\t\u003c!--\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/%3E90%25%20Documented/badge.svg\"\u003e--\u003e\n\t\u003cbr /\u003e\n\t\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/iOS%20Tests/badge.svg\"\u003e\n\t\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/macOS%20Tests/badge.svg\"\u003e\n\t\u003cbr /\u003e\n\t\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/tvOS%20Tests/badge.svg\"\u003e\n\t\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/watchOS%20Build%20Tests/badge.svg\"\u003e\n\t\u003cbr /\u003e\n\t\u003cimg src=\"https://github.com/unsignedapps/Vexil/workflows/Linux%20Tests/badge.svg\"\u003e\n\n## Features\n\n* Define your flags in a structured tree\n* Extensible to support any backend flag storage or platform\n* Take and apply snapshots of flag states\n* Get real-time flag updates using Combine\n* Vexillographer: A simple SwiftUI interface for editing flags\n\n## Documentation\n\nIn addition to this README, which covers basic usage and installation, you can find more documentation on our website: https://vexil.unsignedapps.com/\n\n## Vexil 3 Migration\n\nVexil 3 is currently under active development and is a full rewrite using\n [Swift Macros](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/)\nand the [Visitor Pattern](https://en.wikipedia.org/wiki/Visitor_pattern) to reduce usage of\n[Mirror](https://developer.apple.com/documentation/Swift/Mirror) and memory usage as well as\nimproving the overall performance.\n\nThe document below describes current the current stable 2.x version. If you'd like to learn more about Vexil 3 see\nthe [Migrating Guide](https://swiftpackageindex.com/unsignedapps/vexil/v3.0.0-alpha.1/documentation/vexil/migration2-3).\n\n## Usage\n\n### Defining Flags\n\nIf you've ever used [swift-argument-parser][swift-argument-parser] defining flags in Vexil will be a familiar experience.\n\nVexil supports a tree of flags, so we need a structure to hold them:\n\n```swift\nimport Vexil\n\nstruct LoginFlags: FlagContainer {\n\n    @Flag(\"Enables the forgot password button on the login screen and associated flows\")\n    var forgotPassword: Bool\n\n}\n```\n\n**Side Note:** Vexil requires descriptions for all of its flags and flag groups. This is used by [Vexillographer](#vexillographer-a-swiftui-flag-manipulation-tool) 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.\n\nSee the [full documentation for how to define flags][defining-flags] to read more\n\n### Checking flags\n\nTo check your flags, you need to run them up a Flag Pole:\n\n```swift\nimport Vexil\n\nlet flagPole = FlagPole(hoist: AppFlags.self)\n\n// should we show the change password screen?\nif flagPole.profile.password.changePassword {\n    // ...\n}\n```\n\n### Mutating flags\n\nBy 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`).\n\nThat said, it is still very easy to mutate any flags if you need to using a snapshot:\n\n```swift\nimport Vexil\n\nlet flagPole = FlagPole(hoist: AppFlags.self)\n\nvar snapshot = flagPole.emptySnapshot()\nsnapshot.profile.password.changePassword = true\n\n// insert it at the top of the hierarchy\nflagPole.insert(snapshot: snapshot, at: 0)\n```\n\nFor more info see [Snapshots](#snapshots).\n\n## Flag Value Sources\n\nThe Vexil `FlagPole` supports multiple backend flag sources, and ships with the following sources built-in:\n\n| Name | Description |\n|------|-------------|\n| `UserDefaults` | Any `UserDefaults` instance automatically conforms to `FlagValueSource` |\n| `Snapshot` | All snapshots taken of a FlagPole can be used as a source. |\n\nSee the full documentation on [Flag Value Sources][flag-value-sources] for more on working with sources and how to define your own.\n\n\n## Snapshots\n\nVexil provides a mechanism to mutate, save, load and apply snapshots of flag states and values.\n\n**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.\n\nSnapshots are implemented as a `FlagValueSource`, so you can easily apply multiple snapshots in a prioritised order.\n\nSnapshots can do a lot. See our [Snapshots Guide][snapshots] for more.\n\n## Creating snapshots\n\nYou can manually create snapshots and specify which flags are affected:\n\n```swift\nimport Vexil\n\n// create an empty snapshot\nvar snapshot = flagPole.emptySnapshot()\n\n// update some values and states\nsnapshot.login.forgotPassword = false\nsnapshot.profile.password = false\n\n// apply that snapshot - only the two values above will change\nflagPole.insert(snapshot: snapshot, at: 0)\n```\n\nYou can also take a snapshot of the current state of your FlagPole:\n\n```swift\nimport Vexil\n\nlet flagPole = FlagPole(hoist: AppFlags.self)\n\n// snapshot the current state - this will get the state of *all* flags\nlet snapshot = flagPole.snapshot()\n\n// save them, mutate them, whatever you like\n// ...\n```\n\n## Installing Vexil\n\nTo use Vexil in your project add it as a dependency in a Swift Package, add it to your `Package.swift`:\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/unsignedapps/Vexil.git\", from: \"1.0.0\")\n]\n```\n\nAnd add it as a dependency of your target:\n\n```swift\ntargets: [\n    .target(name: \"MyTarget\", dependencies: [\n        .product(name: \"Vexil\", package: \"Vexil\")\n    ])\n]\n```\n\n### In Xcode 11+\n\nTo use Vexil in Xcode 11 or higher, navigate to the _File_ menu and choose _Swift Packages_ -\u003e _Add Package Dependency..._, then enter the repository URL and version details for the release as desired.\n\n## Vexillographer: A SwiftUI Flag Manipulation Tool\n\nThe second library product of Vexil is Vexillographer, a small SwiftUI tool for displaying and manipulating flags.\n\n![Vexillographer screenshots](https://github.com/unsignedapps/Vexil/raw/main/Sources/Vexillographer/Vexillographer.docc/Resources/screenshots.png)\n\nRead more about [Vexillographer][vexillographer].\n\n## Contributing\n\nWe welcome all contributions! Please read the [Contribution Guide](CONTRIBUTING.md) for details on how to get started.\n\n## License\n\nVexil is available under the MIT license. See the [LICENSE](LICENSE) file for more info.\n\n[vexil-logo]: .github/vexil-banner.png\n[swift-argument-parser]: https://github.com/apple/swift-argument-parser\n\n[defining-flags]: https://vexil.unsignedapps.com/documentation/vexil/definingflags\n[flag-value-sources]: https://vexil.unsignedapps.com/documentation/vexil/sources/\n[snapshots]: https://vexil.unsignedapps.com/documentation/vexil/snapshots/\n[vexillographer]: https://vexil.unsignedapps.com/documentation/vexillographer/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funsignedapps%2FVexil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funsignedapps%2FVexil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funsignedapps%2FVexil/lists"}