Megaparsec is a Haskell parser built around the quality of its errors
Industrial-strength monadic parser combinator library
At a glance
- What is it?
- Megaparsec is an industrial-strength monadic parser combinator library for Haskell that is built around MonadParsec, an MTL-style type class, and its selling point is a third axis of quality alongside speed and flexibility, which is how well a parse failure explains itself. The library also has recovery combinators, typed error bundles, and primitives that make it competitive with Attoparsec.
- Who is it for?
- Megaparsec fits a Haskell project parsing user input, configuration or a domain language where a good error message is part of the feature, because the ParseErrorBundle machinery and the recovery combinators are the reason to pick it over a smaller library. It does not fit a project that needs the raw speed of Attoparsec and cannot afford the generality, and it does not fit a team that wants error handling that is uniform across the whole ecosystem of Haskell parsers.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 25 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
Three axes of quality
The description is a single sentence with a claim in it. This is an industrial-strength monadic parser combinator library, and it is a feature-rich package that strikes a nice balance between speed, flexibility, and the quality of parse errors. That third term is what distinguishes it from the rest of the Haskell parsing ecosystem, because speed and flexibility have been available for a while and error quality is where the effort went. The practical consequence is that a Megaparsec failure is meant to be read by a human, with the position, the expected tokens and the offending input all named. That is a design decision with a cost, since producing a good error message means the library has to track more state than a parser that simply fails. The package is published on Hackage, it is on Stackage nightly and on an LTS snapshot, and the repository carries a CI workflow for it.
MonadParsec is the abstraction you program against
The package is built around MonadParsec, an MTL-style type class, and most features work with all instances of it. That is the architectural centre of the library, because it means the parser type is a parameter rather than a fixed choice. You can achieve various effects by combining monad transformers, that is by building a monadic stack. Since the common monad transformers such as WriterT, StateT and ReaderT are themselves instances of the MonadParsec type class, you can wrap ParsecT in these monads, which the documentation gives as an example of achieving backtracking state. The other half of the design is that ParsecT is an instance of many type classes itself, the most useful being Monad, Applicative, Alternative and MonadParsec. In practice that means a Megaparsec parser composes with the ordinary applicative and alternative machinery, so the parts of a grammar that do not need backtracking can be written without the monadic machinery at all.
Three combinators that Parsec does not have
Megaparsec includes all the functionality typically available in Parsec-like libraries and adds some special combinators of its own. The first is parseError, which ends parsing and reports an arbitrary parse error, so you can raise a domain specific error from anywhere in a grammar rather than only where a token fails to match. The second is withRecovery, which recovers from parse errors on the fly and continues parsing, and once parsing is finished the collected parse errors may be reported or ignored altogether. The third is observing, which makes it possible to observe parse errors without ending the parse. Together those three are what make error handling a first class part of a grammar rather than an exception thrown from inside it, and they are the reason the library is described as industrial-strength rather than merely complete.
The performance primitives and the benchmark
The library also has high-performance combinators of the kind found in Attoparsec, and the README gives the numbers. The tokens combinator makes it easy to parse several tokens in a row, and string and string' are built on top of that primitive, and it is about 100 times faster than matching a string token by token. It returns a chunk of the original input, so if you parse Text it returns Text without repacking. The takeWhileP and takeWhile1P combinators are about 150 times faster than approaches involving many, manyTill and similar combinators, and takeP grabs n tokens from the stream as a chunk. The performance section then compares the two libraries on three test cases, and the results are mixed in an instructive way. On CSV, Megaparsec is faster at 64.69 microseconds against 76.50, with lower allocation and lower max residency. On Log, Attoparsec wins at 302.8 against 337.8 microseconds. Overall, the framing is that Megaparsec is about as fast as Attoparsec if you write your parser carefully, which is the honest summary of the whole comparison.
Error bundles and error positions
The error message section is where the design work shows. Megaparsec has typed error messages and the ability to signal custom parse errors that better suit the domain of interest. The location of a parse error can be independent of the current offset in the input stream, which the documentation says is useful when you want a parse error to point at a particular position after performing some checks, so a validation rule that inspects a whole form can report the line where the offending field is rather than where the parser happened to be. Instead of a single parse error, Megaparsec produces a ParseErrorBundle data type that helps manage multi-error messages and pretty-print them, making it easy to report multiple parse errors at once. The combination of typed errors, custom errors, decoupled positions and bundles is what separates the library from the tradition of a parser that returns a string message.
Streams, lexers and binary input
The library works out of the box with several input stream types, namely String as a list of Char, ByteString in both strict and lazy flavours, and Text in both strict and lazy flavours, and it is also possible to make it work with custom token streams by making them an instance of the Stream type class. That last point is what makes the external lexer story work, since Megaparsec works well with streams of tokens produced by tools like Alex, though the documentation warns that the design of the Stream type class has changed significantly in recent versions and that you can still work with custom streams of tokens. On the character side there is decent support for Unicode-aware parsing in the Text.Megaparsec.Char module and a separate Text.Megaparsec.Byte module for parsing streams of bytes. The Text.Megaparsec.Char.Lexer module is intended to be imported qualified, is not included in the main Text.Megaparsec module, and is there to help you write a lexer, with the claim that if you have used Parsec in the past this module fixes the inflexibility of Text.Parsec.Token. Its design lets you solve simple tasks quickly and stays out of the way when you need something less standard, with white space, comments and indentation as the recurring theme, and a Text.Megaparsec.Byte.Lexer counterpart for binary data.
The project around the library
The repository is a normal Haskell package with a couple of unusual extras. The source lives under the Text/ directory, which is the module hierarchy, with megaparsec.cabal as the package definition, a cabal.project file, a bench/ directory, a megaparsec-tests/ directory for the test suite, and a parsers-bench/ directory that holds the benchmarks the performance table is built from. There is a script/ directory, a HACKING.md for contributors, a CHANGELOG.md, and the project is reproducible with Nix since flake.nix and shell.nix are present. The README compares Megaparsec against five other libraries in separate sections, Attoparsec, Parsec, Trifecta, Earley and Flatparse, and that comparison material is the best single document for deciding whether it fits your project. The licence needs a note. The badge in the README points at the FreeBSD licence, while the project listing records a custom licence that GitHub cannot classify, so the authoritative answer is the LICENSE.md file in the repository. The repository is not archived, the last push was on 2026-09-29, and no GitHub releases are published, so the Hackage version is the artefact to depend on.
Editorial conclusion
Megaparsec fits a Haskell project parsing user input, configuration or a domain language where a good error message is part of the feature, because the ParseErrorBundle machinery and the recovery combinators are the reason to pick it over a smaller library. It does not fit a project that needs the raw speed of Attoparsec and cannot afford the generality, and it does not fit a team that wants error handling that is uniform across the whole ecosystem of Haskell parsers. Before you adopt it, read the comparison sections in the documentation, since the README sets Megaparsec against Attoparsec, Parsec, Trifecta, Earley and Flatparse with the reasoning for each, and check the licence, because the badge points at the FreeBSD licence while the project listing records a custom licence and LICENSE.md is the file to read.
Frequently asked questions
What is Megaparsec?
It is an industrial-strength monadic parser combinator library for Haskell, built around the MonadParsec type class, that aims to balance speed and flexibility with the quality of the parse errors it produces.
What do withRecovery and observing do?
withRecovery recovers from parse errors on the fly and continues parsing, and the collected errors can then be reported or ignored once parsing finishes. observing lets you see parse errors without ending the parse, and parseError ends parsing and reports an arbitrary error of your own.
How does Megaparsec compare to Attoparsec on speed?
It is close. On a CSV test case Megaparsec is faster at 64.69 microseconds against 76.50, while on a Log case Attoparsec wins at 302.8 against 337.8 microseconds, and the README concludes that Megaparsec is about as fast if you write your parser carefully.
Which input types does Megaparsec support?
String, ByteString in strict and lazy form, and Text in strict and lazy form, and custom token streams can be supported by making them an instance of the Stream type class, which is also how it works with lexers such as Alex.
Is Megaparsec still developed?
The repository is not archived and the last push was on 2026-09-29, and no GitHub releases are published, so the Hackage package and the Stackage snapshots are the artefacts to depend on. The README badge points at the FreeBSD licence while the project listing records a custom licence, so LICENSE.md is the file to check.
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/mrkkrp-megaparsec)Was this useful?