Hi everyone,
While working on a modular iOS project with Swift Package Manager, I ran into a common problem: as the number of modules grows, Package.swift quickly turns into a long list of string-based dependencies.
Example:
.target(
name: "NewsPresentation",
dependencies: [
"NewsDomain",
"Core",
"UI",
"Resources"
]
)
This approach works, but it has a few downsides in larger projects:
• dependencies are string-based
• architectural rules are not enforced
• manifests grow with a lot of repetition
• refactoring module names becomes fragile
Since SwiftPM manifests are just Swift files, I experimented with using Swift itself to model the architecture.
The idea is to treat Package.swift not just as configuration, but as a declarative description of the module architecture.
For example, feature modules can be generated from a small DSL:
featureTargets(module: { .News($0) })
Which produces:
with dependency rules encoded once.
Modules and dependencies are represented using enums instead of strings:
.module(.Core)
.module(.News(.Domain))
This gives compile-time safety for dependencies and allows encoding architectural rules directly in Swift.
In my demo project this approach generates 35 modules while keeping the manifest relatively compact.
I wrote a more detailed explanation here:
I would be curious to hear feedback from others using SwiftPM at scale.
Specifically:
• Do you see drawbacks in treating Package.swift as a small DSL for architecture?
• Have you used similar approaches in larger SwiftPM projects?
• Are there better patterns for encoding architectural rules in SwiftPM?
Thanks!
