How do you inspect a package and its dependency graph from the command line?

16.7.6 · L3 · Interview

Predict first

What do describe, show-dependencies and dump-package report for a small app with a local dependency?

// === run.sh ===
export GIT_AUTHOR_NAME=t GIT_AUTHOR_EMAIL=t@t GIT_COMMITTER_NAME=t GIT_COMMITTER_EMAIL=t@t
W=$(mktemp -d); cd $W
mkdir -p Lib/Sources/Lib App/Sources/App App/Tests/AppTests
cat > Lib/Package.swift <<'E'
// swift-tools-version: 6.0
import PackageDescription
let package = Package(name: "Lib", products: [.library(name: "Lib", targets: ["Lib"])], targets: [.target(name: "Lib")])
E
echo 'public let v = 1' > Lib/Sources/Lib/V.swift
cat > App/Package.swift <<'E'
// swift-tools-version: 6.0
import PackageDescription
let package = Package(name: "App", dependencies: [.package(path: "../Lib")],
  targets: [.executableTarget(name: "App", dependencies: [.product(name: "Lib", package: "Lib")]),
            .testTarget(name: "AppTests", dependencies: ["App"])])
E
echo 'import Lib' > App/Sources/App/main.swift
echo 'import Testing' > App/Tests/AppTests/T.swift
cd App
echo "targets: $(swift package describe --type json | python3 -c 'import json,sys; print(sorted((t["name"], t["type"]) for t in json.load(sys.stdin)["targets"]))')"
echo "dependencies: $(swift package show-dependencies --format json | python3 -c 'import json,sys; print([d["name"] for d in json.load(sys.stdin)["dependencies"]])')"
echo "manifest keys include: $(swift package dump-package | python3 -c 'import json,sys; d=json.load(sys.stdin); print([k for k in ("name","platforms","toolsVersion") if k in d])')"
  • targets (App, executable) and (AppTests, test), dependency lib, manifest keys name/platforms/toolsVersion
  • only the root target
  • no output until the package is built

Mental model. These commands are the package’s X-ray: the manifest is what the author wrote, describe is what the build system understood.

Three read-only commands answer most “what does this package actually declare?” questions without opening Xcode. swift package describe --type json prints the evaluated manifest as seen by the build: targets with their type (library, executable, test), sources, products and platforms. swift package show-dependencies prints the resolved dependency tree (--format json for tooling), including each package’s resolved version or path. swift package dump-package prints the manifest’s raw JSON, including keys such as toolsVersion, platforms, targets and, in recent versions, traits. In the check, a small app with a local dependency reports its targets as App (executable) and AppTests (test), the dependency name Lib, and the expected manifest keys.

Why use them: as CI assertions (fail the build if a forbidden dependency appears, or if a target gains an unexpected dependency, which is how a layered module graph is kept honest, Q368), to generate a graph picture or an impact list for “affected builds” (Q373), to debug a conflict (Q619), and to audit third-party licences and sizes. Because the JSON is stable and scriptable, a 20-line script over describe can enforce architecture rules (“feature modules never depend on each other”) much more cheaply than code review. Limits: they describe the package graph, not an Xcode project’s targets (for those use xcodebuild -list or the project file), and they evaluate the manifest, so they need a working toolchain and sometimes network access to resolve remote dependencies first.

These commands read the manifest and graph without compiling anything.

Common traps

  • Parsing Package.swift with a regex. It is Swift code and can compute its contents; ask SwiftPM to evaluate it.
  • Expecting these to cover Xcode project targets. They only know SwiftPM packages.

They might follow up with

  • How do I find which target imports which? The graph is in describe; actual import lines need a source scan, and a check of the two catches undeclared dependencies.
  • Can I get a visual graph? Convert the JSON to Graphviz DOT with a short script.

Related questions

  • 16.7.3 Two dependencies need incompatible versions of a third. What does the resolver say, and how do you get out?
  • 16.1.1 What are targets, products and modules in a Swift package, and what does a first Package.swift look like?
  • 16.3.2 Why must the module dependency graph be acyclic, how do you layer it, and what does its shape do to build…
  • 16.6.1 A CI pipeline takes hours on a large modular app. How do you analyse and cut it: affected builds, caching…

← How do package mirrors work, and when do you use one for a company or…