optparse-applicative: command line parsing as an applicative value
Applicative option parser
At a glance
- What is it?
- optparse-applicative is a Haskell library for parsing command line options where the core type is a Parser with Functor, Applicative and Alternative instances, so a whole option set is assembled with the ordinary applicative operators. It also generates usage lines, help screens and context sensitive bash, zsh and fish completions.
- Who is it for?
- optparse-applicative suits a Haskell developer who wants a command line interface that reads like a value, composes with the applicative operators, and produces a help screen and shell completions without writing the plumbing.
- Can I use it commercially?
- Yes. BSD-3-Clause 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 11 days ago.
- What is it written in?
- Mainly Haskell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One type with three instances
optparse-applicative is a Haskell library for parsing options on the command line and for providing a powerful applicative interface for composing them.
The core of the library is a single type:
data Parser a
instance Functor Parser
instance Applicative Parser
instance Alternative ParserA value of type Parser a represents a specification for a set of options which will yield a value of type a when the command line arguments are successfully parsed. That is the whole abstraction, and it is the reason the library feels different from a hand-written argument loop.
The README is explicit about who the library is for. If you are familiar with parser combinator libraries like parsec, attoparsec, or the json parser aeson you will feel right at home. If not, the advice is that all you really need to learn are a few basic parsers and how to compose them as instances of Applicative and Alternative.
That framing is accurate, and it is also the migration cost. The library assumes you are comfortable with applicative style: a parser is a description of an option set, and the option set is assembled with the same operators you would use for any other applicative. The benefit is that the composition is type-checked and that the resulting value is a plain Haskell record, so nothing about the parsing leaks into the code that uses the result.
The other thing the library takes care of, listed in the README, is reading and validating the arguments, handling and reporting errors, generating a usage line and a comprehensive help screen, and enabling context-sensitive bash, zsh and fish completions.
Builders and modifiers: options, flags, arguments
The primitive parsers come from a Builder interface, and they cover the usual shapes of POSIX style option.
A regular option takes an argument. Here is one for a mandatory String:
target :: Parser String
target = strOption
( long "hello"
<> metavar "TARGET"
<> help "Target for the greeting" )The attributes passed to the option are called modifiers, and they are composed using the semigroup operation, which is (<>). The metavariable and the help text appear in the generated help text and do not otherwise affect the behaviour of the parser.
A flag has no argument and simply returns a predetermined value. The simplest flag is a boolean switch:
quiet :: Parser Bool
quiet = switch ( long "quiet" <> short 'q' <> help "Whether to be quiet" )The short modifier gives the option a one-letter name, so the switch can be set with either --quiet or -q. The value is True if the user types the flag and False otherwise.
The Builders section covers the rest of the vocabulary: regular options, flags, arguments and commands, plus the modifiers that tune them. Arguments are the positional kind, commands are the sub-command form where a program dispatches on a verb, and the modifiers control things like defaults, visibility in the help text, and whether an option may be repeated.
One naming detail is worth flagging for anyone reading the source: what the library calls a regular option is what most people call an option with a value, and what it calls a flag is what others call a boolean option. The vocabulary is consistent inside the library, but it does not match every other tool's vocabulary.
Composition, and why option order does not matter
The quick start builds a record type and a parser for it with the applicative operators:
data Sample = Sample
{ hello :: String
, quiet :: Bool
, enthusiasm :: Int }
sample :: Parser Sample
sample = Sample
<$> strOption
( long "hello"
<> metavar "TARGET"
<> help "Target for the greeting" )
<*> switch
( long "quiet"
<> short 'q'
<> help "Whether to be quiet" )
<*> option auto
( long "enthusiasm"
<> help "How enthusiastically to greet"
<> showDefault
<> value 1
<> metavar "INT" )The `hello` option is a String argument, `quiet` is a switch, and `enthusiasm` is parsed as an Int with help of the Read type class, given a default of 1 and shown in the help text because of showDefault.
The Applicative section then makes the point that matters most for anyone coming from a manual argument loop: no matter which parsers appear first in the sequence, options will still be parsed in whatever order they appear on the command line. That is the difference between a parser that describes the shape of the interface and a parser that dictates the shape of the invocation. A user can write --enthusiasm 3 --quiet --hello world and get the same result as the other order.
The Alternative instance is what makes optionality and sub-commands work, since it is the type class for choosing between parsers. The library's own composition style, which the README calls applicative do, is a way to express a group of options that only make sense together.
Running it, and what the user actually sees
The parser is turned into a program with execParser and a description built by info, whose progDesc and header modifiers set the summary line and the header text:
main :: IO ()
main = greet =<< execParser optsThe helper combinator takes any parser and adds a help option to it, which is why the finished program supports --help without any extra work.
The payoff shows up in the error output. The hello option is mandatory since it does not have a default value, so running the program without any argument displays an error message and a short option summary:
Missing: --hello TARGET
Usage: hello --hello TARGET [-q|--quiet] [--enthusiasm INT]
Print a greeting for TARGETAnd the full help text lists every option with its description:
hello - a test for optparse-applicative
Usage: hello --hello TARGET [-q|--quiet] [--enthusiasm INT]
Print a greeting for TARGET
Available options:
--hello TARGET Target for the greeting
-q,--quiet Whether to be quiet
--enthusiasm INT How enthusiastically to greet (default: 1)
-h,--help Show this help textThis is the reason to use the library rather than hand-rolling. The usage line, the mandatory-option detection, the default display and the grouped short and long flags are all derived from the same description, so they cannot disagree with each other the way a hand-written help string does. The README's table of contents lists a section on customising the help screen, so the layout is adjustable, and sections on disambiguation, preferences and custom option readers for the cases where the defaults do not fit.
Completions, the arrow interface and the rest of the surface
Shell completion is a first-class feature rather than an afterthought. The README says the library enables context-sensitive bash, zsh and fish completions, and the table of contents gives completion its own section with subsections on actions and completers and on internals.
The distinction in that section heading matters. A completion that lists every option of the program is a static list. A completion that offers only the options valid for the sub-command you are currently typing is context sensitive, and that is the behaviour that makes a sub-command based CLI pleasant to use. The library's Actions and Completers model is how that context is described.
The table of contents also lists an Arrow interface and an Applicative Do section. Both address the same practical problem from different directions. The arrow interface is for people who would rather write the parser as a data transformation, and applicative do is for expressing a set of options that belong together. The FAQ and a How it works section are also included, which is a good sign for a library whose behaviour is not obvious from its type signature.
Under custom parsing and error handling there are sections on parser runners, option readers, preferences, disambiguation, customising the help screen and command groups. Parser runners is the one to know about if you are embedding the library in a larger program: it is the hook for taking the argument list from somewhere other than the process arguments, and for deciding what happens when parsing fails.
The repository itself is small and conventional: src/, tests/, optparse-applicative.cabal, Setup.hs, hie.yaml for Haskell IDE Engine support, .hlint.yaml for HLint configuration, CHANGELOG.md and the LICENSE file.
Hackage, the BSD licence and a slow release line
The licence field on the repository says BSD-3-Clause, with the LICENSE file at the top of the tree. The BSD licence is permissive, so using the library in a closed source product carries no obligation beyond retaining the copyright notice, the conditions and the disclaimer. For a library that most consumers will never fork, that is the expected arrangement.
The library is published on Hackage, which is where the README links for downloads and API reference, and the package name in the ecosystem is the same as the repository name.
The release record shows a slow line. The most recent release is 0.19.0, dated 3 June 2025, preceded by 0.18.1 on 2023-07-16 and 0.18.0 on 2023-05-23. The version numbering carries the minor version as the Haskell package version, so 0.19.0.0 is the version in the release title.
The repository is not archived and the last push was on 2026-10-12, so work is still landing on master even though no release has been cut since June 2025. That gap is worth weighing before you depend on it. For a library like this, stability is mostly about the help output format and the completion scripts, which downstream tools sometimes parse, so a change in those is the kind of thing that can break a release script even when nothing in your program changes. CHANGELOG.md is in the repository and is the place to look before upgrading past a version you have not used.
Editorial conclusion
optparse-applicative suits a Haskell developer who wants a command line interface that reads like a value, composes with the applicative operators, and produces a help screen and shell completions without writing the plumbing. It does not suit a team that wants a runtime-configurable option schema, since the parser is built at compile time in Haskell types, and it does not suit anyone who needs the newest option parsing behaviour today, since the newest tag is 0.19.0 from June 2025. Before adopting, write one parser with a required option and a flag, run it with --help to see the generated usage text, and check the error output for a missing required argument, because the quality of those two outputs is the main thing this library is for.
Frequently asked questions
What is optparse-applicative and what is its core type?
It is a Haskell library for parsing command line options, built around a Parser type with Functor, Applicative and Alternative instances. A value of type Parser a is a specification for a set of options that yields a value of type a when the arguments parse successfully.
How do I define an option and a flag with optparse-applicative?
Use strOption for an option with a String argument and switch for a boolean flag, and compose the attributes with the semigroup operator, for example strOption (long "hello" <> metavar "TARGET" <> help "Target for the greeting") and switch (long "quiet" <> short 'q' <> help "Whether to be quiet").
Does the order of options on the command line matter in optparse-applicative?
No. The README states that no matter which parsers appear first in the sequence, options will still be parsed in whatever order they appear on the command line, because the parser is a description of the interface rather than a script for the invocation.
What does optparse-applicative generate besides parsed values?
It handles and reports errors, generates a usage line and a comprehensive help screen, and enables context-sensitive bash, zsh and fish completions. A missing mandatory option produces a message and a short option summary, for example Missing: --hello TARGET with the usage line.
What licence is optparse-applicative under and where is it published?
The licence field on the repository says BSD-3-Clause, and the library is published on Hackage. The newest tag listed is 0.19.0 from 2025-06-03, while the last push to the repository was on 2026-10-12.
Official sources
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.
[](https://hysenlabs.com/projects/pcapriotti-optparse-applicative)Was this useful?