swift-configuration puts one reader in front of many config sources
API package for reading configuration.
At a glance
- What is it?
- Swift Configuration is an Apple package that defines an abstraction between configuration readers and providers, so an application reads values through one API while the source of those values is decided once at the entry point. Values from higher priority providers override lower ones, and package traits keep optional formats out of your build.
- Who is it for?
- swift-configuration fits a Swift server or app that needs environment variables, a config file and command line arguments to compose into one namespace, and it fits library authors who want to accept configuration without imposing a source on the host application.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Readers read, providers are set up once
Swift Configuration is a Swift library for reading configuration in applications and libraries, and its whole design is one sentence: it defines an abstraction layer between configuration readers and providers.
The division of labour is what makes the library useful in two different situations. Applications and libraries read configuration through a consistent API, while the actual provider is set up once at the application's entry point.
That split is the difference between a library that reads configuration and a library that forces its host to configure it. If you write a library that needs a timeout, you can read it through the reader API without caring whether the value came from an environment variable, a JSON file or a default. If you write an application, you decide at startup which providers exist and in what order, and nothing else in the code needs to know.
The library is licensed Apache 2.0, with the licence repeated in LICENSE.txt and a NOTICE.txt file alongside it. Security issues are reported through the process in SECURITY.md, and contributions follow CONTRIBUTING.md. The documentation is on the Swift Package Index, with a video introduction on YouTube and complete working examples in the Examples directory.
Provider order is the priority order
The core behaviour is that multiple providers can be combined in a hierarchy, where values from higher priority sources override those from lower priority ones.
The README works this through with a default configuration in JSON.
{
"http": {
"timeout": 30
}
}And an environment variable that overrides one value in it.
# Environment variables:
HTTP_TIMEOUT=15The code creates the two providers and resolves them in the order listed.
let config = ConfigReader(providers: [
EnvironmentVariablesProvider(),
try await FileProvider<JSONSnapshot>(filePath: "/etc/config.json")
])
let httpTimeout = config.int(forKey: "http.timeout", default: 60)
print(httpTimeout) // prints 15Three things are worth pulling apart here. First, the key is a dotted string, http.timeout, rather than a nested type, so the same accessor works for any source. Second, the default of 60 is passed to the accessor, not to the provider, so the fallback lives with the read site. Third, the resolution outcome is spelled out in the prose: the value is 15 from the environment variable, without the environment variable it would be 30 from the JSON file, and if both sources are unavailable the fallback default of 60 is returned.
That last case is the interesting one. The library does not fail when a source is missing, it falls through to the next source and then to the default. A configuration read is therefore never an error path in your code, which is convenient for a server that would rather start with a default than refuse to boot.
Package traits keep optional formats out of the build
The package uses SwiftPM package traits to add integrations conditionally, and the default trait set is deliberately small.
Enabling a trait means editing the package dependency.
.package(
url: "https://github.com/apple/swift-configuration",
from: "1.0.0",
+ traits: [.defaults, "YAML"]
)The available traits are listed in full. JSON is the default and adds support for FileProvider with a JSONSnapshot, a ConfigProvider for reading JSON files. YAML is opt-in and adds the same for YAMLSnapshot. PropertyList is opt-in and adds FileProvider with a PropertyListSnapshot.
Logging is opt-in and adds AccessLogger, a way to emit access events into a SwiftLog.Logger. CommandLineArguments is opt-in and adds CommandLineArgumentsProvider for parsing command line arguments.
Reloading is opt-in and adds auto-reloading variants of the file providers: ReloadingFileProvider with a JSONSnapshot when JSON is enabled, ReloadingFileProvider with a YAMLSnapshot when YAML is enabled, and ReloadingFileProvider with a PropertyListSnapshot when PropertyList is enabled.
That last trait is worth pausing on, because the dependency is conditional in a way that is easy to miss. The reloading variants exist only for the formats you have actually enabled. Enabling Reloading without YAML gets you a reloading JSON provider and a reloading property list provider if that trait is on, but no reloading YAML provider, because the YAML provider itself is not compiled in. The traits compose rather than substitute.
For a server that should not carry a YAML parser it never uses, this is the mechanism that keeps it out. For a team that adds a format later, the trait list becomes a checklist of what the build actually supports.
What is in the box, and where the docs live
The library ships a set of built-in providers covering the usual sources.
Environment variables are covered by EnvironmentVariablesProvider. Command line arguments by CommandLineArgumentsProvider, which is opt-in. JSON files by FileProvider with a JSONSnapshot and its reloading variant. YAML files by FileProvider with a YAMLSnapshot and its reloading variant. Property list files by FileProvider with a PropertyListSnapshot, and the list of built-in providers is followed by a further section in the README that is cut off in the version shown here.
The documentation strategy is worth noting because it is consistent. The main documentation lives on the Swift Package Index rather than in the repository, and the README links specific pages: configuring applications, configuring libraries, and a page specifically for migrating to Swift Configuration. The examples come in three forms, an overview of use cases on the package index, an Examples directory in the repository, and the snippets in the README itself.
The repository has a Benchmarks directory, which tells you the maintainers care about the cost of the abstraction rather than just its ergonomics. There are also Examples subdirectories for a hello world CLI example and a reloading example, which are the two configurations you most want to see working end to end.
The repository root has a .spi.yml file for the Swift Package Index, a .swift-format configuration and a .swiftformatignore file, plus an .licenseignore file, which together suggest a release process with formatting enforced and licence headers checked.
The platform floor is the real adoption constraint
The supported platforms list is short but demanding.
The library is supported on Apple platforms, Linux, Windows and Android. The minimum versions are macOS 15+, iOS 18+, tvOS 18+, watchOS 11+ and visionOS 2+, plus Linux, Windows and Android API 28+.
This matters more than it looks for a configuration library. Configuration code sits at the bottom of an application, so its deployment target is the union of everything the application supports. If your app still supports macOS 13 or iOS 16, adopting this package means either raising your own minimum or keeping a separate configuration path, which is exactly the duplication the abstraction was supposed to remove.
The Linux, Windows and Android entries have no version constraints of their own beyond the Android API level, which is consistent with a package that depends on Foundation and Swift concurrency rather than on any Apple-only framework. The Apple platform minimums are the strict part, and they are the part to plan around.
On the release side, the version history shows 1.2.0 on 2026-03-05, 1.2.1 on 2026-09-21 and 1.2.2 on 2026-10-05, and the last push to the repository was on 2026-10-20. The package is past 1.0 and still taking patch releases, so the API surface is expected to be stable, and the README documents a migration guide for people arriving from another configuration approach.
Where swift-configuration is the wrong tool
The first limitation is that the provider set is fixed. The built-in providers cover environment variables, command line arguments, and JSON, YAML and property list files. The README does not describe an extension point for a custom source, so if your configuration comes from a vault, a remote control plane, a Kubernetes ConfigMap through a custom API, or a secrets manager, you would be writing that integration yourself or wrapping the reader rather than extending it.
The second limitation is that it is a Swift package. The abstraction is elegant and the API is well shaped, but if part of your system is not Swift, this does not help. A Python service and a Swift service in the same system will end up with two configuration mechanisms unless one of them reads a file the other writes, which reintroduces the coupling the library is trying to remove.
The third is the platform floor, covered above, and the fourth is that a configuration library that never fails to read can hide a missing source. The fallback chain means a typo in an environment variable name or a file that was never deployed produces a working application with a default value rather than an error. That is the right default for a server that should keep serving, and it is the wrong default for a job that must be configured correctly, and the library gives you one behaviour for both.
The fifth is scope. This is a reader, not a schema validator. There is no mention of required fields, type validation beyond the int accessor, or a way to fail a startup on a malformed configuration file beyond the throwing FileProvider initialiser.
How it compares with reading a config file yourself
The alternative most Swift projects start from is to read a file, decode it into a struct, and pass it around. That approach has real virtues. It is explicit, it is typed end to end, and the compiler tells you when the shape changes. A JSON file decoded into a Codable struct with non-optional fields will fail loudly at startup if the file is wrong.
The cost of that approach is that every source becomes special. Environment variables need their own accessor, because you cannot decode them into a struct without writing that code. Command line arguments need a parser. And the moment a library needs one value from configuration, either the library takes a typed parameter and every call site changes, or the library reaches for the environment itself and the testability goes with it.
swift-configuration takes the opposite trade. Access is uniform, dotted keys with a typed accessor and a default, so a library can read a value without the host deciding how it arrives. The cost is that the type safety moves from compile time to the accessor, and the configuration shape is a set of strings rather than a struct.
The middle path is common in practice: use the library to compose the sources into one reader at the entry point, then snapshot the reader into your own typed struct at startup and pass that struct down. You keep the composability and you keep the type safety, at the cost of one conversion layer. The README's guide for configuring libraries is the page to read for how the library wants that boundary drawn.
Against other languages' configuration libraries, the distinctive part is the traits mechanism rather than the API, because it lets a package ship JSON by default and keep YAML, property lists, logging, reloading and command line parsing out of a build that does not want them.
Editorial conclusion
swift-configuration fits a Swift server or app that needs environment variables, a config file and command line arguments to compose into one namespace, and it fits library authors who want to accept configuration without imposing a source on the host application. It does not fit a project that needs a configuration format the package does not implement, since the provider list is fixed and custom sources are not described in the documentation shown here, and it does not fit a team pinned to older platforms, since the minimum is macOS 15, iOS 18, tvOS 18, watchOS 11 and visionOS 2. Before adopting, decide which traits you need, since YAML, property lists, command line arguments, logging and reloading are all opt-in and the reloading variants only exist for the file formats you have enabled, and read the guide for configuring libraries, because that is where the reader versus provider split changes how much of the setup the host owns.
Frequently asked questions
What is swift-configuration and what problem does it solve?
It is a Swift library for reading configuration in applications and libraries. It defines an abstraction layer between configuration readers and providers, so code reads values through a consistent API while the provider is set up once at the application's entry point.
How do I add swift-configuration to a Swift project?
Add the dependency to Package.swift with .package(url: "https://github.com/apple/swift-configuration", from: "1.0.0"), add .product(name: "Configuration", package: "swift-configuration") to your target, then import Configuration and create a ConfigReader with the providers you want.
How does priority work when I use several configuration providers?
Providers are resolved in the order you list them, and values from higher priority sources override those from lower priority ones. The README example lists EnvironmentVariablesProvider first and a FileProvider with a JSONSnapshot second, so an environment variable wins over the JSON file, and a default passed to the accessor is used when neither source has the key.
What are the package traits in swift-configuration?
JSON is the default trait and adds FileProvider with a JSONSnapshot. YAML and PropertyList are opt-in and add their own file providers, Logging is opt-in and adds AccessLogger for emitting access events into a SwiftLog.Logger, CommandLineArguments is opt-in and adds CommandLineArgumentsProvider, and Reloading is opt-in and adds auto-reloading variants of the file providers.
Which platforms and versions does swift-configuration support?
The library is supported on Apple platforms, Linux, Windows and Android. The minimums are macOS 15+, iOS 18+, tvOS 18+, watchOS 11+ and visionOS 2+, plus Linux, Windows and Android API 28+.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/apple-swift-configuration)Was this useful?