# hmlongco/Factory: Container-Based Dependency Injection for Swift and SwiftUI

> Factory registers dependencies as computed properties on a Container and resolves them through @Injected or direct calls. It is compile-time safe and small, but it is not a service locator replacement for every architecture.

**hmlongco/Factory** — A modern approach to Container-Based Dependency Injection for Swift and SwiftUI.

- Repository: https://github.com/hmlongco/Factory
- Stars: 2,903 · Forks: 194
- Language: Swift
- License: MIT
- Published: 2026-09-24 · Updated: 2026-09-24 · Language: en
- Canonical page: https://hysenlabs.com/en/projects/hmlongco-factory

## The problem Factory solves for Swift and SwiftUI teams

Swift has no built-in dependency injection container. Without one, a view model that needs a network service and a logger typically constructs them itself, which makes substituting a mock in a unit test or a SwiftUI Preview awkward. Factory addresses that by giving each dependency a name and a closure that produces it, then letting call sites ask for that name instead of constructing the object. The README frames the target audience broadly: UIKit or SwiftUI, iOS or macOS, and MVVM, MVP, Clean or VIPER all work, because the container does not impose a pattern. The practical audience is a team already writing SwiftUI views and wanting their previews and tests to receive different implementations without editing production code.

## How registration and resolution actually work

A registration is a computed property on Container that returns a Factory of the service type. The README shows the sugared form, where self { MyService() } stands in for Factory(self) { MyService() }, and states both are equivalent. Resolution happens through the @Injected property wrapper, which takes a keyPath to a factory and resolves when the enclosing type is created. The README is explicit that this is compile-time safe: the factory must exist in the specified container and must return the desired type, or the code will not compile.

Factory structs are described as lightweight and transitory value types, created inside computed variables only when needed and discarded afterwards, so building them on the fly is not a cost concern according to the README. Beyond @Injected, the README lists calling the factory directly as a function (Container.shared.myService()), passing a container into a view model initializer, using the container as a composition root, and a global dependency(\\.preferences) function that can be replaced to reduce visible coupling to Factory.

## Installing Factory and resolving your first dependency

The repository ships a Package.swift and a Factory.podspec, so the two distribution routes visible in the layout are Swift Package Manager and CocoaPods. The README does not print an install command block, so the package URL is the one to add in Xcode under Package Dependencies. Once the package is linked, the README's registration example looks like this:

```swift
extension Container {
    var myService: Factory<MyServiceType> {
        self { MyService() }
    }
}
```

The README then shows resolution through the @Injected property wrapper, which takes a keyPath to a factory of the desired type:

```swift
class ContentRepository {
    @Injected(\.myService) private var myService
    ...
}
```

If you prefer to skip the property wrapper, the README shows calling the factory directly as a function, which returns an instance of the managed dependency:

```swift
@Observable
class ContentViewModel {
    @ObservationIgnored
    private let myService = Container.shared.myService()
    @ObservationIgnored
    private let eventLogger = Container.shared.eventLogger()
    ...
}
```

After adding the dependency and building, the compiler should accept the registration and the @Injected keyPath; a missing factory or a type mismatch is reported as a compile error rather than a runtime failure.

## Mocks, previews and the cost of a container

The README's mocking section asks the obvious question: why not just write let myService = MyService() and be done with it. The answer it builds toward is that a container lets tests and previews substitute a different implementation for the same keyPath without touching the type that consumes it. That is the real value proposition, and it is why the project markets itself as testable and previewable. The trade-off is that every dependency now has a name in a container, and readers of a call site must follow that name to learn what is being constructed. Teams that dislike indirection will find the extra hop annoying even though each registration is one line.

## Where Factory is the wrong choice

Factory is a compile-time construct. Registrations live in code, keyed by keyPath, and there is no runtime registry the README describes for loading implementations from configuration or plugins. If your requirement is to choose an implementation at runtime from a remote flag or a downloaded module, this design does not serve it; you would be fighting the compile-time safety that is the project's stated selling point. It is also a poor fit for a codebase that cannot introduce a Container type, for example a small module with no shared container and no interest in one. And because resolution through @Injected happens when the enclosing type is created, an object graph with cycles or heavy eager construction needs care that the README does not walk through.

## How Factory differs from Swinject and Resolver

Swinject is the long-standing Swift DI container that centers on an Assembler and explicit register and resolve calls, with registrations collected at runtime and lookups that can fail at runtime. Resolver, by the same author as Factory, uses a similar registration model. Factory's difference is that a registration is a computed property returning a typed Factory, and resolution through @Injected is checked by the compiler, so a missing or mistyped registration is a build error rather than a nil or a crash. The README also claims under 1,000 lines of executable code and no compile-time scripts or build phases, which is a smaller footprint than a container that leans on code generation. The cost of that choice is less flexibility for runtime registration, as noted above.

## Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-09-16, the same day as the 3.4.0 release. The two prior releases, 3.3.2 and 3.3.1, landed in July 2026, so the release cadence over that window is roughly two months. Factory is MIT licensed, which permits commercial use and modification provided the copyright notice and permission notice are included; that is a summary of the licence text, not legal advice. Upgrade cost is dominated by the Package.swift pin and by any API you use that changed between 3.3.x and 3.4.0. The repository carries a CHANGELOG and a Factory.xctestplan, and the README points to DocC documentation on the project site, which is where to look before bumping the version.

## Conclusion

Factory fits Swift and SwiftUI codebases that want explicit, compile-time-checked registrations without a build phase, especially where unit tests and SwiftUI Previews need swapped dependencies. It is a poor fit for projects that want runtime-resolved registrations or that cannot adopt a container type. Before adopting, verify that the pinned version in Package.swift matches the API you plan to use, that the MIT licence terms suit your distribution, and that the resolution style you pick (property wrapper, direct call, or global dependency function) is one the DocC documentation actually covers for your case.

## FAQ

### What is hmlongco/Factory used for?

It is a container-based dependency injection library for Swift and SwiftUI. You register a dependency as a Factory computed property on a Container, then resolve it with @Injected or by calling the factory directly.

### How do I install hmlongco/Factory in an Xcode project?

The repository includes a Package.swift, so it can be added as a Swift Package Manager dependency, and it also ships a Factory.podspec for CocoaPods. The README does not print an install command, so use the package URL in Xcode's Package Dependencies panel.

### Is hmlongco/Factory compile-time safe?

The README states that a factory for a given type must exist in the specified container and must return the desired type, otherwise the code will not compile. That is the mechanism behind its compile-time safety claim.

### What licence does hmlongco/Factory use?

It is released under the MIT License. The repository contains a LICENSE file and the README describes the project as free and open source under that licence.

### Does hmlongco/Factory support mocking for tests and SwiftUI Previews?

The README lists unit tests and SwiftUI Previews among the supported features and has a dedicated mocking section. It argues that a container lets you substitute an implementation for the same keyPath without changing the consuming type.

## Sources

- [hmlongco/Factory on GitHub](https://github.com/hmlongco/Factory)
- [Issues](https://github.com/hmlongco/Factory/issues)
- [License: MIT](https://github.com/hmlongco/Factory/blob/main/LICENSE)
- [README](https://github.com/hmlongco/Factory/blob/main/README.md)
- [Releases](https://github.com/hmlongco/Factory/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/en/projects/hmlongco-factory
