CLI tool
apple/swift-argument-parser avatar
apple/swift-argument-parser

apple/swift-argument-parser: type-safe command-line parsing for Swift tools

Straightforward, type-safe argument parsing for Swift

3,777 stars416 forksSwiftApache-2.0

At a glance

What is it?
Swift Argument Parser turns a Swift struct into a CLI by reading property wrappers. It is the parsing layer under swift-format and Swift Package Manager, Apache-2.0 licensed, and it sets a hard floor on your Swift toolchain version.
Who is it for?
Adopt swift-argument-parser if you are writing a Swift executable and want help text, error messages and subcommand routing derived from your own types. Do not adopt it if your tool must build on a Swift release older than the one your chosen release requires, or if you need a parser that is not tied to the Swift toolchain.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: hand-rolled argv parsing in Swift executables

A Swift command-line tool that parses its own arguments ends up with a loop over CommandLine.arguments, a switch on string prefixes, and a pile of manual validation. Every new flag means another branch, and the help text drifts out of sync with the code that actually reads the flags. Error output is whatever the author remembered to write.

Swift Argument Parser replaces that loop with a type. You declare a struct, annotate its stored properties, and conform to ParsableCommand. The library reads the property names and types, parses argv against them, instantiates the type, and calls run(). The audience is Swift developers shipping executables through Swift Package Manager: internal tools, developer utilities, and the command-line front ends of larger Swift projects. The README lists swift-format and swift-package-manager as adopters, and swift-package-manager is cited for a deep command hierarchy and heavy use of option groups, which tells you the library is expected to scale past a single command with three flags.

How the property wrappers drive parsing and help output

The mechanism is property wrappers plus type information. @Argument marks a positional value, @Option marks a named value that takes a parameter, and @Flag marks a boolean switch. The declared Swift type of the property decides how the string from the command line is converted: an Int property is parsed as an integer, a String property is taken as-is, and an optional type makes the value non-required. The default value you assign in the property declaration becomes the value used when the flag is absent.

The same declarations generate the help text and the error messages, which is the part that saves real work. In the README's repeat example, a missing positional argument produces Error: Missing expected argument 'phrase'. followed by a Help line, a Usage line and a pointer to --help. The --help output is grouped into ARGUMENTS and OPTIONS sections, and the help strings come from the help: arguments you passed to the wrappers. Note the boundary the README draws: the exact wording and formatting of the autogenerated help and error messages are explicitly not part of the public API and may change in any release. If you assert on help output in tests, that is a fragile place to stand.

For concurrent code, AsyncParsableCommand is the variant to conform to instead of ParsableCommand. The README notes this directly, and the count-lines example in the repository uses async/await in its implementation. Nested commands and subcommands are covered by the math example, and the default-as-flag example demonstrates options that behave as both a flag and a value-taking option.

Installing swift-argument-parser and writing a first command

There is no standalone installer. The library is a Swift Package Manager dependency, so you add it to an existing package and to the executable target that will use it. The README gives the dependency declaration with a from: "1.7.0" version requirement and the product name ArgumentParser.

swift
let package = Package(
    dependencies: [
        .package(url: "https://github.com/apple/swift-argument-parser", from: "1.7.0"),
    ],
    targets: [
        .executableTarget(name: "<command-line-tool>", dependencies: [
            .product(name: "ArgumentParser", package: "swift-argument-parser"),
        ]),
    ]
)

After resolving, import ArgumentParser in the file that declares your command. The README's first example is a repeat tool with a flag, an optional count option and a required positional phrase. It is a complete program: the @main attribute makes it the entry point, and run() holds the logic.

swift
import ArgumentParser

@main
struct Repeat: ParsableCommand {
    @Flag(help: "Include a counter with each repetition.")
    var includeCounter = false

    @Option(name: .shortAndLong, help: "How many times to repeat 'phrase'.")
    var count: Int? = nil

    @Argument(help: "The phrase to repeat.")
    var phrase: String

    mutating func run() throws {
        let repeatCount = count ?? 2
        for i in 1...repeatCount {
            if includeCounter { print("\(i): \(phrase)") } else { print(phrase) }
        }
    }
}

Run the built executable as repeat hello --count 3 and the README shows hello printed three times. Run it as repeat --count 3 with the phrase omitted and you get the missing-argument error, the help line for <phrase>, and a usage string of repeat [--count <count>] [--include-counter] <phrase>. That usage string is generated, not written by hand. The repository's Examples directory holds further programs to read: repeat, roll, math, count-lines and default-as-flag.

Toolchain and version constraints you inherit

The README's supported-versions table is the constraint that bites hardest. Releases 1.8.0 and later require Swift 6.0. The range 1.3.0 ..< 1.7.1 requires Swift 5.7, 1.1.0 ..< 1.3.0 requires 5.5, 0.2.0 ..< 1.1.0 requires 5.2, and 0.0.1 ..< 0.2.0 requires 5.1. If your tool must build on an older toolchain, the table tells you which release line is even available to you, and it may not be the newest one.

The README goes further and states the policy plainly: new versions are expected to require clients to upgrade to a more recent Swift toolchain, and requiring a new Swift release only needs a minor version bump. A minor-version update can therefore break your build environment without breaking the API. That is a real operational cost for a tool that ships to users who pin their own toolchains. The package is described as source-stable, with source-breaking changes to public API only in a new major version, and the public API is defined as the non-underscored declarations marked public in the ArgumentParser module. Interfaces outside that set, including the help and error text, the examples, the tests and the documentation, may change in any release.

When swift-argument-parser is the wrong choice

The library is bound to Swift and to Swift Package Manager as the distribution path. A tool written in another language cannot use it, and a Swift program built without SwiftPM does not get the dependency declaration from the README. If your project ships a binary to users who never run swift build, the parser still works, but every upgrade decision runs through the toolchain table above rather than through your own release cadence.

The second limit is the definition of the public API. Because help and error wording are outside it, a tool whose interface contract includes exact stderr text cannot treat that text as stable. Teams that test CLI output byte for byte will find those assertions break on minor upgrades, and the README says so rather than pretending otherwise.

The third is scale of ambition. The library covers arguments, options, flags, nested subcommands and option groups, and the README points at swift-package-manager for the deep-hierarchy case. It does not claim to be a general shell-completion framework or a config-file loader, and the README does not describe either. If you need those, they are separate problems you still have to solve.

Compared with parsing argv by hand

The alternative most Swift developers actually weigh is no dependency at all: read CommandLine.arguments, match on strings, and print your own help. That approach has no toolchain floor and no version churn. It also has no generated usage line, no automatic missing-argument error, and no type conversion, so every option needs its own parsing and validation code, and the help text is maintained by hand next to that code.

The difference is where the truth lives. With a hand-rolled parser, the set of accepted flags is whatever the switch statement happens to handle, and the help text is a second copy of that knowledge that can drift. With ArgumentParser, the struct is the single declaration: the property wrapper, the type and the help string together define what is accepted and what the user is told. The cost is a dependency whose minor releases can raise your minimum Swift version, and whose generated output you cannot pin as a contract. For a small tool with two flags, hand-rolling is defensible. For a tool with subcommands, option groups and users who will read --help, the generated surface is the reason to take the dependency.

Editorial conclusion

Adopt swift-argument-parser if you are writing a Swift executable and want help text, error messages and subcommand routing derived from your own types. Do not adopt it if your tool must build on a Swift release older than the one your chosen release requires, or if you need a parser that is not tied to the Swift toolchain. Before committing, verify the minimum Swift version for the release you pick against the table in the README, and check whether you need AsyncParsableCommand rather than ParsableCommand.

Frequently asked questions

Is Swift used for iOS?

This question is about the Swift language rather than swift-argument-parser. swift-argument-parser is a Swift Package Manager library for building command-line tools, and the README describes its use in Swift executables, not in iOS apps.

Should I use argparse?

Python's argparse is a different library in a different language. If you are writing a Swift executable, swift-argument-parser is the equivalent choice: declare a type conforming to ParsableCommand, annotate its properties with @Argument, @Option and @Flag, and implement run().

What compiler does Swift use?

This question concerns the Swift toolchain generally. The relevant fact here is that swift-argument-parser sets a minimum Swift version per release, from 5.1 for the earliest versions up to Swift 6.0 for 1.8.0 and later.

What is Swift as a programming language?

This question is about Swift itself, not about swift-argument-parser. The library is written in Swift and distributed through Swift Package Manager, and the README states that the package is source-stable with semantic versioning.

Official sources

  1. apple/swift-argument-parser on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/apple-swift-argument-parser.svg)](https://hysenlabs.com/projects/apple-swift-argument-parser)