Open-source project
snowballstem/snowball avatar
snowballstem/snowball

Snowball compiles one stemming language into thirteen targets

Snowball compiler and stemming algorithms

885 stars211 forksCBSD-3-Clause

At a glance

What is it?
Snowball is a small string processing language for writing stemming algorithms, with a compiler that emits source code in Ada, C, C++, C#, Dart, Go, Java, JavaScript, Object Pascal, PHP, Python, Rust and Zig. It suits anyone who needs a language-specific stemmer and is willing to read a specification, and it is deliberately conservative about what it stems.
Who is it for?
Snowball suits a team that needs a stemmer for a language no off-the-shelf package covers, or that wants to control exactly which transformations are applied and how ambiguous cases are resolved.
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 6 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

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

Editorial analysis

A language for describing suffixes, not a dictionary of them

Snowball is described as a small string processing language for creating stemming algorithms for use in Information Retrieval, plus a collection of stemming algorithms implemented using it. That second half matters: this is both a tool and a library of finished algorithms.

The design rationale is worth understanding, because it explains what the generated code does and does not do. Snowball maps different forms of the same word to a common stem, with the English stemmer mapping connection, connections, connective, connected and connecting to connect, so that a search for connected also finds documents with the other forms.

Then comes the part that keeps it from being over-eager. The stem form is often a word itself, but that is not a requirement for the text search systems that are the intended field of use. The project also aims to conflate words with the same meaning rather than all words with a common linguistic root, so awe and awful do not get the same stem, and over-stemming is more problematic than under-stemming, so the algorithms tend not to stem in cases that are hard to resolve.

The README draws the line plainly: if you want to always reduce words to a root form, or to get a root form which is itself a word, then Snowball's stemming algorithms likely are not the right answer. That is a stemmer, not a lemmatiser, and a team that has confused the two will be disappointed.

The historical note explains the rest. Snowball was originally designed and built by Martin Porter, who retired from development in 2014, and it is now maintained as a community project. The name was originally a tribute to SNOBOL, the string handling language from the 1960s, and it now also serves as a metaphor for how the project grows by gathering contributions over time.

One compiler, thirteen target languages

The Snowball compiler translates a Snowball program into source code in another language. The current list is Ada, C, C++, C#, Dart, Go, Java, Javascript, Object Pascal, PHP, Python, Rust and Zig.

That list is the practical reason to look at this project. A stemmer for a language nobody has written one for is a genuine problem, and the usual answers are bad: adapting an existing English stemmer to another language produces incorrect results, and a hand-written stemmer is a project in itself. The Snowball approach is to write the algorithm once in a language designed for describing string rewriting, and pay a compile step for the target.

The generated code is the deliverable that matters. The README says the compiler is written in ISO C and that you need a C compiler supporting C99 to build it, but adds a reassuring detail: the C code it generates should work with any ISO C compiler. So the build constraint is on the compiler itself, not on what the compiler produces, which is what you want when the output has to build inside somebody else's project on a platform you do not control.

The repository layout reflects the structure. There is a compiler directory for the compiler source, an algorithms directory for the stemmer definitions, and then one directory per target language, among them csharp, dart, go, java, javascript, pascal, php, python, rust and zig, plus ada, cxx and the libstemmer directory. There are also charsets, include, runtime, tests, examples and doc directories, and a GNUmakefile at the root.

The examples directory carries a single file, stemwords.c, and a top-level iconv.py, which suggests the character set handling is a Python tool rather than something bolted onto the compiler.

The build is two stages, and the reason is distribution

Building Snowball requires GNU make, and the README is explicit that the build system is structured as two separate stages for many of the target languages. The reason it is explained at this length is that the staging is the design.

The first stage builds the Snowball compiler and runs it to create target language code, and it can also run the tests on each stemmer. The expectation is that you then create distribution tarballs of this code with make dist, or one for a specific target language, for example with make dist_libstemmer_c for C. The tarballs are created in the dist subdirectory.

To actually build the libstemmer library you then unpack and build the distribution tarball, and the C case is given as an example:

bash
tar xf dist/libstemmer_c-3.2.0.tar.gz
cd libstemmer_c-3.2.0
make

The staging exists so that the compiler, which needs a native C99 toolchain, is not a build dependency of the library on the user's machine. A consumer of libstemmer_c gets a self-contained tarball with generated C source and builds that with whatever compiler they already have. For a distribution packager this is the difference between a package that builds anywhere and one that needs a specific host toolchain at build time.

Cross-compiling is handled with the same principle, and the README spells out the ordering. If cross-compiling starting from the git repo, the Snowball compiler needs to be built with a native compiler, then libstemmer with the cross-compiler:

bash
make CC=cc dist_libstemmer_c
tar xf dist/libstemmer_c-3.2.0.tar.gz
cd libstemmer_c-3.2.0
make CC=riscv64-unknown-linux-gnu-gcc

There is a Windows wrinkle, and it is a real one rather than a cosmetic caveat. When cross-compiling to or from Microsoft Windows you need to work around an assumption in the libstemmer Makefile which sets EXEEXT based on the OS you are building on, and the example given for cross-compiling from Linux to Microsoft Windows is to use something like make CC=x86_64-w64-mingw32-gcc EXEEXT=.exe. Going the other way, you need to use EXEEXT=.

The pattern is: build the compiler natively, generate the target source, then build the target with the cross-compiler and the right EXEEXT. A packager who skips the first stage will not get a working library.

What is in the repository, and what a consumer actually takes

The top-level entries show two things living side by side: the tool and the outputs.

The tool side is the compiler directory, the algorithms directory holding the stemmer definitions, the doc directory, and the GNUmakefile. The output side is the per-language directories and libstemmer, which is the C library form of the output and the one most search systems actually consume.

The charactersets, include and runtime directories are shared pieces. The charsets directory holds character set definitions, which is what a stemming algorithm needs to know about multi-byte and case-folding behaviour, and the include and runtime directories hold the support code each generated implementation needs. The tests directory is where the stemmers are checked, and since the compiler can run the tests on each stemmer as part of the first build stage, a change to a Snowball program is validated before it reaches the distribution tarball.

That last point is the one that matters for a team considering the project. A stemmer is a set of rules about suffixes, and the rules interact: a step that strips plural endings can change what a later step sees. The ability to run the tests on each stemmer during the build is what turns the algorithm definitions into something you can change with confidence.

For a consumer who does not want to write a stemmer, the same tests are a reference. The algorithms directory is a catalogue of existing stemmers, and reading one is a fast way to understand what the language can express before deciding to write one.

The project is under a BSD-3-Clause licence, with a COPYING file at the root and an AUTHORS file. There are no GitHub releases, and the last push to the repository was on 2026-10-17. The documentation site is snowballstem.org, and the README points there for more information.

Where the approach stops being the right one

The clearest limit is already stated by the project and is worth repeating without softening, because it is the mistake teams make most often with a stemmer.

Snowball is not a lemmatiser. It maps related surface forms to a common stem, and it deliberately declines to resolve cases that would require knowing the word's dictionary form. It aims to conflate words with the same meaning rather than words with a common root, so awe and awful stay apart, and it avoids stemming in cases that are hard to resolve because over-stemming is more damaging than under-stemming.

For an English search engine, that trade is usually right. For a system that needs to know that running, ran and run are forms of one word, or that better and best share a root but not a meaning, a stemmer is the wrong instrument, and the README says so.

The second limit is coverage. Snowball ships stemmers for the languages it ships stemmers for, and the set is not the set of all languages. A team needing a stemmer for a language with no algorithm in the algorithms directory has to write one in the Snowball language, which means learning a small language designed for exactly this, and the documentation site is where that learning happens.

The third is the build. The two-stage process is a deliberate and sensible design, but it is more moving parts than a package manager expects, and the Windows EXEEXT workaround shows where the friction lands. A distribution that wants to package a stemmer has to reproduce the staging, and the cross-compilation ordering in the README is not optional.

None of that makes the project hard to recommend for its actual use. It makes it a compiler and a specification rather than a drop-in library, and an adopter should know which of the two they are buying.

Editorial conclusion

Snowball suits a team that needs a stemmer for a language no off-the-shelf package covers, or that wants to control exactly which transformations are applied and how ambiguous cases are resolved. It is the wrong tool for a search system that would be better served by a full morphological analyser, because the README is explicit that Snowball maps related forms to a common stem rather than resolving a word to its root, and it is the wrong tool for anyone who wants a ready-made stemmer without writing one. Before you adopt it, read the source distribution for the language you care about, confirm the two-stage build in your packaging works, and check whether an existing stemmer for your language is already in the algorithms directory before writing a new one.

Frequently asked questions

What is Snowball and what does the Snowball compiler do?

Snowball is a small string processing language for creating stemming algorithms for use in Information Retrieval, and the Snowball compiler translates a Snowball program into source code in another language. Ada, C, C++, C#, Dart, Go, Java, Javascript, Object Pascal, PHP, Python, Rust and Zig are currently supported.

How do I build Snowball and the libstemmer library?

GNU make is required. The first stage builds the compiler and generates target language source, and you create a distribution tarball with make dist, or make dist_libstemmer_c for C. You then unpack that tarball and run make inside it to build the library.

How do I cross-compile a Snowball stemmer?

Build the Snowball compiler with a native compiler first, then build libstemmer with the cross-compiler, for example make CC=cc dist_libstemmer_c followed by make CC=riscv64-unknown-linux-gnu-gcc. When targeting Windows you also need to set EXEEXT=.exe, because libstemmer's Makefile assumes the OS you are building on.

Is Snowball a lemmatiser?

No. It maps related forms of a word to a common stem and does not resolve words to a root form, and it deliberately avoids stemming in cases that are hard to resolve because over-stemming is more problematic than under-stemming. The README says that if you always want a root form, Snowball's algorithms are likely not the right answer.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. Project website
  4. README
  5. snowballstem/snowball 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/snowballstem-snowball.svg)](https://hysenlabs.com/projects/snowballstem-snowball)

Was this useful?