Use of SPM for internal modules?

How can I create and add a Swift Package to my app, where the source folder for the package is a subfolder within the same repo? How can I add it to my app in a way that is unversioned? (I.e. we only have the app's version; we want to use Swift Packages purely to define modules but don't need any of SPM's "dependency management" trappings.)

Here's some background if it matters:

My org's app is broken about 40 frameworks that comprise various features and shared code. Recently we migrated to a monorepo, so none of our own projects rely on any kind of per-framework versioning or dependency management system anymore.

Still though, having 40 frameworks in the workspace means lots of Xcode project files and so, refactors than move files around for example can cause nasty merge conflicts in the .pbproj files. And when someone makes a new project there is always some setting in the project that gets set wrong and we have build problems.

So now that project resources can be included to a Swift Package as of Swift 5.3, we are beginning to consider if it makes sense to migrate away from using frameworks and use Swift Packages for everything instead.

However when I was trying to convert one framework into a Swift Package, it seems that Swift Packages are really only intended for a situation where the Swift Package comes from its own git repo (and not just some local subfolder in the same repo as the app).

As well it seems like the "dependency management" aspect is rather baked into the concept of a Swift Package—it seems to expect that rebuilding only needs to happen if the package version changed.

But we don't want these packages to be versioned, and we don't want them to exist in another repo or for SPM/Xcode to look for them anywhere on a network. We just want to use them as modules, that's it.

How can we?


If you create another directory and put the Package.swift and all of its source files in there you can drag that into your app. You will need to manually link the libraries when you do it this way. It has worked well overall for my current project.

I do this all the time for small tools and utilities I spin up. Swift Packages make it really easy to declare separate modules for things. You would have a root Package.swift manifest that can reference other packages by relative file path instead of a git repository URL. Those subpackages can be in the same repository (or completely outside of source control if you want).

In fact, you could merely have a single root Package.swift file and just declare separate modules in there and a single root product that depends on them. You don't even need to have a tree of local packages to get this up and running quickly.

With the latest versions of Xcode, if you double click on the Package.swift file, it will open up as a project you can manipulate.


Wow, thanks for the prompt replies! You guys are awesome.

I will try this. Maybe what was confusing me was Xcode's UI for adding packages.

Maybe what was confusing me was Xcode's UI for adding packages.

You’re not the first to say that.

  1. As @Braden_Scothern said, when you want to use a local unversioned package, simply drag its directory into the file list on the left side in your client Xcode project. (Remember to drag the directory containing Package.swift, not the Package.swift file itself. That trips a lot of people.)
  2. Xcode will ask to create a workspace if you haven’t already. (Edit: Only if you drop it in the global scope.)
  3. After that, you’ll be able to add any of the package libraries to any target with the “+” under “Frameworks, Libraries, and Embedded Content”.

That’s all there is to it.


It's not necessary to create a workspace, local packages can also be referenced from projects.


Trying it now, it appears you are right and it depends on where precisely in the list your drag ends. I guess it never occurred to me to drop it anywhere besides the very top or bottom of the list, so I always got the prompt to create a workspace.


Yah, I think it is a little finicky and unless you know both are possible it's easy to miss. I'm going to think about how this could be made more obvious.


When you realize that you can add local packages similar to nested project files it is easy. I think Apple could clear this up by adding a local package option in the “Swift Packages” project settings since I think that is what someone would try first intuitively. It is unintuitive that there are two completely different workflows for adding packages based on local or remote. Once you get it, it works great. You can even run tests as usual.


This has been working great so far.

Only issue we have is that if we include a package's test target in a different scheme with other test targets, then @testable import Package never works from inside its own tests. No idea why not.

I tried to use local packages to organize our codebase, but found a limitation that it is not possible to mix local and remote dependencies (versionBasedDependencyContainsUnversionedDependency). It makes it impossible to use SPM for internal modules and expose something outside with "umbrella" Package.swift. Can someone comment if this is something fundamental or not?

This is a limitation that I would like to see us lift in the future. As far as I know, it is just policy.


I relation to using SPM or nested Xcode Projects. It seems the SPM is evolving to a preferred approach. What are the benefits of sticking with Xcode projects now?

It is not yet possible to run a custom build tool as a build phase in a Swift package.
However, there is an accepted proposal SE-0303 for that being worked on!

There are a ton of bugs around using Swift Packages (SPs) to declare internal modules and Apple is extremely slow at addressing them. Apple does not even try to test this use case or listen to feedback on how horrible of an experience it is.

Trust me if your team does not want headaches, don't do it. If you do it anyway then you will find out why I said it's a headache.

If your app is Swift-only and ALL your internal modules are declared as packages and NONE of them need to import a prebuilt binary from a folder on disk and you don't need a way to remotely cache third-party dependencies and you won't be using Carthage or Cocoapods and you have a skilled developer who can dedictate themselves to resolving weird SP issues and you are OK with using ugly hacks to solve problems and you don't mind waiting for years to get bugfixes then maybe you'll be fine, but heed my warning, it won't be pretty.


@vitamin your post is very much wrong and full of hyperbole.

We have fully embraced SwiftPM for internal app modules when SwiftPM was first added to Xcode and it works great. You can still use non SwiftPM dependencies you just have to inject the dependency over into your package modules.

Although @vitamin's post is maybe overly aggressive, I have to agree with him. We use Swift packages for internal modules and also have some external dependencies. We don't use anything else for dependencies and still we have multiple issues:

  • Xcode 13 crashes when resolving Swift Packages and building the project is not possible at all in Xcode 13 even with clearing everything and trying other workarounds (it builds in Xcode 12.5)
  • In Xcode 12.5 building only works after two tries (it doesn't work with a clean build directory) and even then sometime it randomly doesn't build
  • This all although we already implemented weird workarounds for Swift Packages with binary dependencies
  • When switching branches, Xcode needs to be restarted and the SPM cache needs to be cleared, otherwise it won't build

All these issues are discussed in depth in other threads in this forum and multiple bug reports / radars have been filed but they are not fixed in Xcode 13.0.

Oh it for sure has issues and can be greatly improved. I more than often than not also have to restart it when swapping branches. I haven’t run into not being able to build issues for a long time with it, that said I know a lot of people do experience that issue.

Terms of Service

Privacy Policy

Cookie Policy