Library / SDK
pointfreeco/swift-dependencies avatar
pointfreeco/swift-dependencies

Point-Free's Dependencies: making clocks, UUIDs and dates controllable in Swift

A dependency management library inspired by SwiftUI's "environment."

2,199 stars195 forksSwiftMIT

At a glance

What is it?
A Swift dependency management library built on property wrappers and an environment-like value type, aimed at codebases where Date(), UUID() and Task.sleep have made tests slow and non-deterministic.
Who is it for?
Dependencies earns its place when a feature is hard to test for reasons other than its own logic, which is exactly the situation the README describes with Date(), UUID() and Task.sleep. The property wrapper keeps adoption incremental, since you annotate one field at a time, and the .dependencies trait means a test override is scoped to a single function rather than a whole suite.
Can I use it commercially?
Yes. MIT 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 2 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 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Dependencies are the things you do not control

The README's definition is deliberately broad: dependencies are the types and functions in your application that interact with outside systems you do not control. It names API clients first, then widens the frame to `UUID` and `Date` initializers, file access, user defaults, clocks and timers. The point of including the innocuous ones is that they are the ones actually hurting you.

Three consequences are listed. Uncontrolled dependencies make fast, deterministic tests hard because of network connectivity, file systems and server uptime. Many dependencies do not work in SwiftUI previews at all, with location managers and speech recognizers named as examples, and some do not work in simulators either, such as motion managers. And third-party libraries such as Firebase or websocket clients are heavyweight and slow to compile, which drags on the development cycle.

The second half of the README is more interesting than the first, because it describes the problems that appear once you have solved the first set. How do you propagate dependencies through an app in a way more ergonomic than passing them explicitly but safer than a global? How do you override them for one portion, such as a test or a SwiftUI preview, or one user flow like onboarding? And how do you know you overrode everything a feature touches, rather than mocking two of its four dependencies and leaving the rest to hit the network? That last question is the one most dependency injection setups answer badly, and it shapes the API more than anything else in the library.

The property wrapper is the whole adoption story

Usage starts by declaring a property rather than calling a global function. The README's quick start model annotates four dependencies on an `@Observable` class:

swift
@Observable
final class FeatureModel {
  var items: [Item] = []

  @ObservationIgnored
  @Dependency(\.continuousClock) var clock
  @ObservationIgnored
  @Dependency(\.date.now) var now
  @ObservationIgnored
  @Dependency(\.mainQueue) var mainQueue
  @ObservationIgnored
  @Dependency(\.uuid) var uuid

  // ...
}

The `@ObservationIgnored` attributes are not decoration. Under Swift's observation macro, a stored property becomes observable, and a clock or a queue handle does not need to be, so the annotation tells the macro to leave it alone. Anyone porting this pattern to a plain class can drop that attribute.

From there the call sites change but the shape does not. The README's next example replaces `Task.sleep`, `UUID()` and `Date()` with calls through the declared properties, so the feature's logic reads the same while the sources become swappable. That is the migration story in its entirety: annotate, then substitute at the call site.

What arrives in the box is the `DependencyValues` collection, which the README points to for the full list. The presence of `continuousClock`, `date.now`, `mainQueue` and `uuid` as ready-made values is what makes the library useful on day one, before you have written a single dependency of your own.

Three overrides is the whole test

Testing is where the design either holds up or does not. The README's example uses a `.dependencies` test trait that takes a closure, and the overrides are three lines:

swift
$0.clock = .immediate
$0.date.now = Date(timeIntervalSinceReferenceDate: 1234567890)
$0.uuid = .incrementing

The test then constructs `FeatureModel()` with no arguments and calls `addButtonTapped()`. Because the clock is `.immediate`, a one-second sleep costs nothing. Because the UUID is `.incrementing`, the identifier is deterministic. Because the date is pinned to a fixed interval, the assertion can compare a literal `Date` rather than a tolerance window.

The README frames this as a numbered three-step process: override the dependencies, construct the model, assert. The point worth carrying into your own codebase is that the override happens at the test boundary, not in a shared setup. That is what makes it possible to answer the third question from the overview, whether all of a feature's dependencies were actually controlled. An override scoped to one test function either covers a dependency or it does not, and the compiler-visible form makes the coverage list readable.

The trait requires `Dependencies`, `DependenciesTestSupport` and `Testing`, so the example is built on Swift Testing rather than XCTest. That is consistent with the rest of the package's tooling.

Three Package.swift files for three toolchain eras

The repository root carries `Package.swift` plus `[email protected]` and `[email protected]`. SwiftPM selects a version-specific manifest by toolchain, which is how one package can declare different dependency sets for different compilers rather than forcing everyone onto one. If you are integrating this into an app that still builds with an older toolchain, that directory listing is the first thing to check.

The `Makefile` is more revealing about the project's real support matrix, and it contains an inconsistency you will notice quickly. The `test-swift` target is two lines, run in debug and then release:

bash
swift test -Xswiftc -D -Xswiftc EXCLUDE_EXPORTS
swift test -c release -Xswiftc -D -Xswiftc EXCLUDE_EXPORTS

It is wrapped by a `test-linux` target that runs the same work inside a `swift:6.3-noble` container, while the static standard library target runs in `swift:6.1-focal`. Both images appear in the same Makefile, and the README does not explain the split. The actionable reading is that the Docker images track the oldest toolchain each particular build configuration needs rather than a single supported version, so if you are pinning a Swift version in CI, the image tag that matters depends on which target you invoke.

The same Makefile also builds for a wide set of destinations, looping over iOS Simulator, macOS, Mac Catalyst, tvOS Simulator and watchOS Simulator under a `build-all-platforms` target, and there is a `build-for-library-evolution` target that emits module interfaces for both `Dependencies` and `DependenciesMacros`. The second of those needs a special define to build swift-syntax, with the Makefile linking to an upstream swift-syntax pull request explaining why. That is a small but real signal: the macro target has a non-obvious build requirement.

A steady release line and one low-traffic repository

The release history is regular and small. Version 1.16.0 on 2026-08-18 brought back preview traits and improved `@DependencyEntry` diagnostics. Version 1.17.0 on 2026-08-24 added `DependencyValues.preferredLocales`, changed dependency endpoints to initialize through storage rather than a computed property, eagerly prepared dependencies in the preview trait, and removed the dependence on XCTestDynamicOverlay. Version 1.17.1 on 2026-08-28 was infrastructure only, bumping to support IssueReporting 2.1. The last push to the repository is dated 2026-08-28.

That 1.16.0 note is worth pausing on. Preview traits were removed and then brought back, so anyone who adopted 1.15.x and built a preview setup on those traits had a working pattern invalidated and then restored. The changelog is honest about it, which is more than most projects manage.

The adoption numbers are modest and healthy: 2,195 stars, 195 forks and only 14 open issues. Fourteen issues on a library with this much usage is a very low ratio, and it is worth reading two ways. Either the community reports carefully, or the project absorbs a lot of discussion on Slack rather than in issue trackers, and the README does carry a Slack invite badge alongside the CI badge.

The library was, by the README's own account, designed over the course of many Point-Free episodes, hosted by Brandon Williams and Stephen Celis. That origin explains both the vocabulary and the ergonomics: the questions in the overview section read like a lecture outline because they are one.

What adopting this actually costs

The honest case against is that this is a library with its own mental model, and the model has layers. A property wrapper gets you started, `DependencyValues` is the registry behind it, there is a separate test support module, a macros target for `@DependencyEntry`, traits for SwiftUI previews, and prepared values for the dozens of endpoints the README says ship out of the box. An app already using a conventional container or Xcode's preview mechanism has something working, and this asks for a migration rather than an addition.

There is also the compile-time consideration the README raises in its own list of problems with third-party dependencies, which applies here with some irony. Any dependency that ships macros pulls in swift-syntax, and the Makefile shows that target needing an extra define to build. For a library whose stated purpose is to reduce compile drag from heavyweight dependencies, the build graph is more involved than a small package would suggest.

On the other side, the property wrapper design means adoption is incremental in a way most dependency frameworks are not. You can annotate a clock in one model this afternoon, write one test with `.immediate`, and see whether the result is faster and less flaky before committing the codebase to it. The README is written to support exactly that order of operations, presenting the quick start as sufficient and everything beyond it as available when needed.

Editorial conclusion

Dependencies earns its place when a feature is hard to test for reasons other than its own logic, which is exactly the situation the README describes with Date(), UUID() and Task.sleep. The property wrapper keeps adoption incremental, since you annotate one field at a time, and the .dependencies trait means a test override is scoped to a single function rather than a whole suite. The costs are real and worth naming: the package has its own macros, its own concepts to learn, and a Makefile that spans Swift 6.1 and 6.3 Docker images depending on which target you run. Start by wrapping the clock and the UUID in one model, write the test with .immediate and .incrementing, and only then decide whether the rest of the codebase needs the same treatment.

Frequently asked questions

How does swift-dependencies compare with a SwiftUI environment value?

The library is inspired by SwiftUI's environment and borrows its ergonomics, but it targets SwiftUI previews as well as XCTest and Swift Testing. It also covers dependencies that are not view values at all, such as continuous clocks, date initializers and UUID generators, which have no natural place in a SwiftUI environment.

How do I override a clock in a test with Point-Free Dependencies?

Declare the dependency on your model with @Dependency(\.continuousClock) and override it in the test through the .dependencies trait by assigning $0.clock = .immediate. The README presents this as a three-step pattern of overriding dependencies, constructing the model, then asserting, which keeps each override scoped to a single test function.

Does swift-dependencies require Swift Testing or does it work with XCTest?

The README's example imports Testing along with Dependencies and DependenciesTestSupport, so the documented path is Swift Testing. The project also ships a separate DependenciesTestSupport module and has been removing its XCTestDynamicOverlay dependence, which suggests XCTest interop is supported but the primary target is Swift Testing.

What Swift versions does swift-dependencies build against?

The repository ships three manifests: Package.swift, [email protected] and [email protected], so SwiftPM picks a manifest matching your toolchain. The Makefile is less uniform, using a swift:6.3-noble image for Linux tests and swift:6.1-focal for the static standard library build.

Official sources

  1. License: MIT
  2. pointfreeco/swift-dependencies on GitHub
  3. Project website
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pointfreeco-swift-dependencies.svg)](https://hysenlabs.com/projects/pointfreeco-swift-dependencies)