Library / SDK
scala/scala-parser-combinators avatar
scala/scala-parser-combinators

scala-parser-combinators: the parsing library that left the standard library

simple combinator-based parsing for Scala. formerly part of the Scala standard library, now a separate community-maintained module

678 stars131 forksScalaApache-2.0

At a glance

What is it?
scala-parser-combinators is a community-maintained Scala module, guided by the Scala team at Akka, that parses with combinators instead of generated parsers. It is deliberately plain Scala with no macros, and the README is equally direct about the trade: stability and simplicity in exchange for performance and error reporting.
Who is it for?
scala-parser-combinators fits a Scala team writing a hand-written parser for a config format, a DSL or a small language, who values an unremarkable API and a decade of use over raw throughput. It is the wrong choice for ingesting large volumes of data, for projects that need structured error messages with positions, and for anyone who wants a parser generator instead of a runtime combinator library.
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 30 days ago.
What is it written in?
Mainly Scala, 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

A standard library module that had to leave the standard library

The project description carries the history in one line: it was originally part of the Scala standard library and is now a separate community-maintained module. The README adds that it is maintained under the guidance of the Scala team at Akka, formerly Lightbend, and names two maintainers to contact about joining the team.

That origin explains both the API and the attitude. Parsing combinators in Scala were part of the standard library for years, so the shape of the API is the one that millions of lines of existing Scala code already use. Anyone porting an old parser off scala.util.parsing.combinator will find the same package name waiting for them.

The repository layout reflects how a cross-platform library is built in Scala. There are separate directories for jvm, js and native, which are the three back ends, plus a shared directory holding the code common to all of them. The README states that multiple Scala versions, specifically 2.12, 2.13 and 3, are supported on all back ends, and the Maven Central badges confirm separate artifacts for each. The build is driven by build.sbt in the project directory.

The licence is Apache-2.0, with both a LICENSE file and a NOTICE file at the root, which matters for a module that was previously distributed as part of the standard library: the terms are explicit rather than inherited, and the NOTICE file records the attribution history that Apache-2.0 requires when code has moved between projects.

The README lists its own weaknesses, which is unusual

Most library READMEs sell. This one argues both sides, and the negatives are specific enough to be useful in an evaluation.

The strengths it claims are stability, with the note that it has been around and in wide use for more than a decade, a modest codebase with fairly simple internals, plain vanilla Scala with no macros, code generation or other magic, and support for several Scala versions across the JVM, JavaScript and Native back ends.

The weaknesses it names are performance, with the advice that if you are ingesting large amounts of data you may want something faster, a minimal feature set, and inflexible, unstructured error reporting.

That last one deserves more attention than it usually gets, because it is the failure that hurts users rather than throughput. A parser combinator library reports failure as a message and a position. It does not build a tree of expected alternatives, and it does not tell you the furthest position reached across all alternatives. For a compiler, a linter or a form validator where a user needs to know all the ways their input could be valid, that is a real gap, and no amount of care in your own grammar will fix it.

The README also points to a list of other Scala parsing libraries on Scaladex, and describes this one as simple combinator-based parsing for Scala. The positioning is honest: this is the boring option, and the article's judgement should be whether boring is what you want.

Adding the dependency, and the same library for Scala.js and Native

The dependency goes into build.sbt in the usual %% form, where the double percent expands to the binary version suffix for your Scala version:

scala
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % <version>

For Scala.js and Scala Native the operator changes to %%%, which picks the right platform artifact:

scala
libraryDependencies += "org.scala-lang.modules" %%% "scala-parser-combinators" % <version>

That distinction is the practical payoff of the three-directory repository layout. The same parser code can run in a server, in a browser through Scala.js, or compiled to a native binary, and the artifacts are published for each combination.

For projects that need to support several Scala versions at once, the README points to the scala/scala-module-dependency-sample repository for the pattern.

The version you write in that placeholder is your choice, and the Maven Central badges show the latest release per Scala line, which is a different number for each binary version. The release history in the project shows 2.3.0 in April 2023, 2.4.0 in April 2024, and 2.5.0 on 2026-09-08, so the current line is 2.5.0 and the module is still on the 2.x series despite having been part of the standard library before version 2.10 of Scala. That version numbering, inherited from its standard library days, is a small trap for anyone who assumes the major version tracks recent Scala releases.

How the example parser works: RegexParsers, combinators, three outcomes

The README's example is small enough to read in one pass and complete enough to show the model. A parser is a class extending RegexParsers, with one method per production, and the methods are combined with the ~ operator:

scala
import scala.util.parsing.combinator._

class SimpleParser extends RegexParsers {
  def word: Parser[String]   = """[a-z]+""".r       ^^ { _.toString }
  def number: Parser[Int]    = """(0|[1-9]\d*)""".r ^^ { _.toInt }
  def freq: Parser[WordFreq] = word ~ number        ^^ { case wd ~ fr => WordFreq(wd,fr) }
}

Each production returns a Parser of some type. RegexParsers supplies the regex-based primitives, and the ^^ operator turns a matched string into a typed result. The ~ operator sequences two parsers, and the final ^^ pattern-matches the pair to build the result value.

The entry point is the parse method, and it returns one of three outcomes rather than throwing. Success carries the parsed value, Failure carries a message for input that simply did not match, and Error carries a message for input that could never be valid. The example matches on all three and prints them differently.

Distinguishing Failure from Error is the part worth internalising. A Failure means try something else, which is what a combinator library does constantly while backtracking. An Error means stop, the input is wrong in a way more input will not fix. A parser that wants to abort early, for example when a required field is missing rather than merely unrecognised, can raise an Error to prevent the combinator machinery from continuing to try alternatives. The distinction gives you control over when to give up, which is more control than the error reporting criticism usually implies, even if the messages themselves stay flat.

Where this library is the wrong tool

The two clearest wrong-tool cases are both stated in the README.

The first is volume. If you are ingesting large amounts of data, the README says you may want something faster. This is the expected cost of a runtime combinator approach: a grammar is data, and interpreting it costs more per byte than a generated parser, where a tool turns the grammar into code at build time. The trade is deliberate, since the library refuses macros and code generation. That refusal is a feature for teams that dislike build-time magic, and it is also why the library cannot compete with a generated parser on throughput.

The second is error reporting quality. If your parser is user-facing, whether a form validator, a configuration loader explaining a bad file, or a linter, the flat message style becomes a product problem. You will end up wrapping the library to produce better diagnostics, and at that point you have built the error machinery yourself.

A third case is worth naming even though the README does not: a grammar that is large and heavily ambiguous. Backtracking combinator parsers can be very slow on pathological grammars, and the library does not offer the machinery to control that, since it keeps the feature set minimal.

The feature set being minimal also means no lexer-generator integration, no left recursion support of the kind some libraries provide, and no support for a separate token stream with positions tracked per token. Those are not omissions by accident; they are the cost of a small, simple codebase.

Documentation, examples and how to get help

The documentation set is short and points in three directions. The API reference is on javadoc.io, with the current API for the 2.13 artifact. The Getting Started guide lives in the repository at docs/Getting_Started.md and is where the README sends anyone who wants a detailed unpacking of the example. And for something more substantial, the README links a third party article called Building a lexer and parser with Scala's Parser Combinators.

The reference to chapter 33 of Programming in Scala, Third Edition is a sign of how well established this subject is. That chapter covers combinator parsing with arithmetic expressions and then examines how the library is implemented, which is unusual documentation for a small library and a good sign for someone trying to understand the internals rather than just use them.

The contribution guidance is also specific. The README points to the Scala Developer Guidelines for general rules, to the existing issues, and to GitHub Discussions for questions, and it explicitly invites draft pull requests with partially completed changes to get feedback early.

So the documentation story is: a short getting started guide, a full API reference, a book chapter, and an article. That is thin in volume compared with a modern library with a documentation site, but it is enough to learn the library, and the API reference is the part that matters for day to day use.

Version 2.5.0, a September 2026 push, and what it means for adoption

The release history is slow and steady. Version 2.3.0 was published on 2023-04-26, 2.4.0 on 2024-04-18, and 2.5.0 on 2026-09-08. The last push to the repository was on 2026-09-23, and the repository is not archived.

Two years between 2.3.0 and 2.4.0, and then a two and a half year gap to 2.5.0, tells you this is a maintenance-mode library rather than an actively evolving one. That is not a criticism, because the API has been stable for a decade and the value of such a library comes from its stability. It does mean two things for adoption.

First, you should not expect new features. The feature set is minimal by design and the README says so. If you need error recovery, token positions or lexer generation, you are not going to get them here, and waiting will not change that.

Second, the stability claim and the maintenance record point in the same direction, which is unusual and useful. A library that has been around for more than a decade, ships under Apache-2.0 with a NOTICE file, is built by a community team with named maintainers, and is published for three Scala versions on three back ends is a low-risk dependency. The risk here is not that it breaks, it is that it never grows to meet a requirement you did not anticipate.

The repository has a CODE_OF_CONDUCT.md, a .mailmap file and a .github directory, and the contribution guidance points at the Scala project conventions, which tells you this module is run under the wider Scala project's rules rather than as an independent project.

Editorial conclusion

scala-parser-combinators fits a Scala team writing a hand-written parser for a config format, a DSL or a small language, who values an unremarkable API and a decade of use over raw throughput. It is the wrong choice for ingesting large volumes of data, for projects that need structured error messages with positions, and for anyone who wants a parser generator instead of a runtime combinator library. Before adopting it, read the Getting Started guide, decide whether the error reporting will satisfy your users, and benchmark your own input sizes rather than trusting a general impression of its speed.

Frequently asked questions

How do I add scala-parser-combinators to an sbt build?

The README shows libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % <version> in build.sbt, using %%% instead of %% for Scala.js and Scala Native.

Is scala-parser-combinators still part of the Scala standard library?

No, it was originally part of the standard library but is now a separate community-maintained module under the guidance of the Scala team at Akka.

What are the known weaknesses of scala-parser-combinators?

The README names performance, which it says may not suit ingesting large amounts of data, a minimal feature set, and inflexible, unstructured error reporting.

Which Scala versions does scala-parser-combinators support?

Scala 2.12, 2.13 and 3 are supported, and the README states they work on all back ends, meaning JVM, JS and Native.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. scala/scala-parser-combinators on GitHub
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/scala-scala-parser-combinators.svg)](https://hysenlabs.com/projects/scala-scala-parser-combinators)

Was this useful?