/commands/swift/swift-package-init
swift package init --type executable: create a Swift package
- tool
- Swift
- versions
- Swift 5.x – 6.x
- os
- macos, linux, windows
swift package init --type executable creates a new Swift Package Manager project in the current directory: a Package.swift manifest and a Sources/ folder with the executable target's code. The package takes its name from the directory, or from --name. Build and run it with swift run; use --type library for a reusable module.
Create, build, run
mkdir Hello && cd Hello
swift package init --type executable
swift build # debug build in .build/debug
swift run # build and run the executable
swift build -c release # optimized build in .build/release
swift test # run tests in Tests/What the executable template creates
The getting-started guide on swift.org shows the layout for swift package init --name MyCLI --type executable:
.
├── Package.swift
├── Sources
│ └── MyCLI
│ └── MyCLI.swift
└── Tests
└── MyCLITests
└── MyCLITests.swiftPackage.swift declares the package, its products and targets. Each folder under Sources/ is one target, and the folder name must match the target name in the manifest. The entry point is either a main.swift file with top-level code or a type marked @main; a target cannot have both. Build output goes to .build/ (change it with --scratch-path), which belongs in .gitignore.
Package types
| --type | Creates |
|---|---|
| library (default) | A library target, a test target and a library product other packages can depend on |
| executable | An executable target you can swift run; start here for a small program |
| tool | An executable that uses Swift Argument Parser (Swift 5.9+); start here for a CLI with many options |
| macro | A Swift macro package (Swift 5.9+); pulls in swift-syntax |
| build-tool-plugin | A plugin that runs during the build, for example to generate source files |
| command-plugin | A plugin you invoke on demand with swift package <command> |
| empty | Only Package.swift, for laying out targets by hand |
Other useful options
| Option | Effect |
|---|---|
| --name NAME | Package name; the default is the name of the current directory |
| --package-path DIR | Create the package in DIR instead of the current directory |
| --enable-swift-testing / --disable-swift-testing | Generate tests for the Swift Testing library, or not |
| --enable-xctest / --disable-xctest | Generate tests for XCTest, or not |
Run swift package init --help to see the list for the installed toolchain; the template set and the test options depend on the Swift version.
Add a dependency
// swift-tools-version: 5.9
import PackageDescription
let package = Package(
name: "Hello",
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.0"),
],
targets: [
.executableTarget(
name: "Hello",
dependencies: [.product(name: "ArgumentParser", package: "swift-argument-parser")]
),
]
)swift package resolve # fetch dependencies and write Package.resolved
swift package update # move to the newest allowed versionsThe first comment line, // swift-tools-version:, is required: it sets the minimum Swift version that can read the manifest and the manifest API available. swift package resolve records the exact versions it picked in Package.resolved; commit that file for executables so every build uses the same dependency versions. For a library, the version requirement in from: is what consumers see, so keep it as loose as your code allows.
FAQ
Does swift package init create a new folder?
It works on the package path, which is the current directory unless you pass --package-path. Create and enter the folder first, or pass --name to set the package name independently of the folder name.
What is the difference between --type executable and --type tool?
Both produce a program you can swift run. The tool template also adds a dependency on Swift Argument Parser and a command type that parses options, which is the better start for a CLI with flags.
Can I use main.swift and @main together?
No. A target has either a main.swift file with top-level code or a type marked @main as its entry point, not both.