Contents

swift-primitives/swift-dependency-primitives

Dependency-injection primitives for Swift — a Dependency namespace of typed keys, live/test value variants, and task-local scoped resolution, with zero platform dependencies.

Quick Start

Dependency is the vocabulary for type-safe dependency injection: a key type names a dependency and supplies a liveValue (production) and a testValue (tests); Dependency.Values holds overrides keyed by those types; Dependency.Scope installs them into task-local storage for the duration of an operation. No global singletons, no service locator — resolution is explicit, typed, and scoped.

import Dependency_Primitives

// Declare a dependency by conforming a key type to `Dependency.Key`.
// `liveValue` is used in production; `testValue` in test contexts.
enum APIBaseURL: Dependency.Key {
    static var liveValue: String { "https://api.example.com" }
    static var testValue: String { "https://stub.local" }
}

// Resolve from the current scope. Unregistered keys return the key's default.
let url = Dependency.Scope.current[APIBaseURL.self]   // "https://api.example.com"

// Override for the duration of an operation — overrides also survive `await`.
let staged = Dependency.Scope.with { values in
    values[APIBaseURL.self] = "https://staging.example.com"
} operation: {
    Dependency.Scope.current[APIBaseURL.self]
}
// staged == "https://staging.example.com"

Scopes nest: an inner with overrides only the keys it touches and the parent's values are restored on exit. The same with(_:operation:) is available in synchronous, throwing (with a typed throws), and async forms, so scoped dependencies flow across suspension points.

A values container can also be flipped into a test context, where unregistered keys resolve to testValue instead of liveValue:

import Dependency_Primitives

var values = Dependency.Values.forTesting()
values[APIBaseURL.self]   // "https://stub.local" — the testValue
values.isTestContext      // true

Dependency.Values is a Sendable, copy-on-write value type, so a container can be handed across isolation domains and mutated without disturbing the original.


Installation

dependencies: [
    .package(url: "https://github.com/swift-primitives/swift-dependency-primitives.git", branch: "main")
]
.target(
    name: "App",
    dependencies: [
        .product(name: "Dependency Primitives", package: "swift-dependency-primitives"),
    ]
)

Requires Swift 6.3.1 and macOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26 (or the matching Linux / Windows toolchain).


Architecture

One library product. Depends only on the Witness primitive — Dependency.Key refines Witness.Protocol.

| Product | Target | Purpose | |---------|--------|---------| | Dependency Primitives | Sources/Dependency Primitives/ | The Dependency namespace: Dependency.Key (typed keys with liveValue / testValue variants), Dependency.Values (type-safe heterogeneous storage with value semantics), and Dependency.Scope (task-local scoped resolution in synchronous, typed-throwing, and async forms). |

Foundation-free.


Platform Support

| Platform | Status | |----------|--------| | macOS 26 | Full support | | Linux | Full support | | Windows | Full support | | iOS / tvOS / watchOS / visionOS | Supported |


Community

License

Apache 2.0. See LICENSE.md.

Package Metadata

Repository: swift-primitives/swift-dependency-primitives

Default branch: main

README: README.md