What are targets, products and modules in a Swift package, and what does a first Package.swift look like?

16.1.1 · L3 · Interview

Predict first

For this package, what does swift package describe report as targets and products?

// === Package.swift ===
// swift-tools-version: 6.0
import PackageDescription
let package = Package(
    name: "Demo",
    products: [.library(name: "Core", targets: ["Core"]), .executable(name: "app", targets: ["App"])],
    targets: [
        .target(name: "Core"),
        .executableTarget(name: "App", dependencies: ["Core"]),
    ]
)
// === Sources/Core/Core.swift ===
public struct Greeter {
    public init() {}
    public func hello() -> String { "hello" }
    func hidden() -> String { "hidden" }
    package func pkg() -> String { "pkg" }
}
// === Sources/App/main.swift ===
import Core
print(Greeter().hello())
  • ['Core', 'App'] ['Core', 'app']
  • ['Core'] ['Core']
  • ['App'] ['app']

Mental model. A package is a warehouse. Targets are the rooms where goods are made, each with its own door list (dependencies), and products are the items on the shop shelf. Customers can only buy products, never walk into the rooms.

A package’s Package.swift is Swift code that builds a Package value. Its three central ideas: a target is a directory of sources compiled together with its own settings and dependencies; each target (other than a plain resource or binary one) becomes a module with the target’s name, which other code imports. A target is one of several kinds: .target (a library module), .executableTarget (has an entry point: main.swift or @main), .testTarget, .binaryTarget (a prebuilt .xcframework), .plugin and .macro. A product is what the package exports: a .library (to depend on from other packages or apps; it can contain several targets and be .static, .dynamic or left automatic), an .executable, or a plugin. Targets are internal building blocks; only products are visible to clients, so a target that is not part of any product cannot be imported by another package. Dependencies come in two kinds: target dependencies inside the package (dependencies: ["Core"]) and package dependencies (.package(url:from:) or .package(path:)) whose products you name with .product(name:package:).

The conventions that make it work: sources live in Sources/<TargetName>/, tests in Tests/<TargetName>Tests/, and the swift-tools-version comment on the first line decides which manifest features are available (and, for tools 6, the default language mode). Useful commands: swift build (debug by default; -c release for optimised), swift test, swift run, swift package describe (shows targets and products; add --type json for scripts), swift package resolve and update (fetch and pin dependency versions in Package.resolved) and swift package clean. In Xcode you add a local or remote package to an app, then link its products to the app’s targets; an app can itself be split across several local packages, which is the usual way to modularise (one package, several targets, or several packages). Keep each target small and cohesive, give it an explicit list of dependencies, expose only what clients need, and treat the manifest as the single description of the module graph.

There are two targets (the library and the executable) and two products: the library Core and the executable app.

Common traps

  • Expecting to import a target that is not in any product. Other packages can only use exported products.
  • Putting everything in one big target. It defeats incremental builds and boundaries; split by cohesion and dependency.

They might follow up with

  • What is the difference between a target and a product? A target is a compiled module inside the package; a product is what is offered to clients.
  • Where do sources go? Sources/<TargetName>/, with tests in Tests/<TargetName>Tests/.

Related questions

  • 16.1.2 How do internal, package and public work between modules, and what are the classic surprises?
  • 16.2.1 How do Swift Package Manager, CocoaPods, Carthage and XCFrameworks compare, and how do you choose?
  • 16.3.1 How do static and dynamic linking differ for an app, what do they cost at launch and in size, and what are…

How do internal, package and public work between modules, and what… →