# marisa-trie, memory-efficient tries for Python

> marisa-trie gives Python static, immutable trie-like structures backed by the marisa-trie C++ library, and its argument is a memory one, since string data in a MARISA trie may take up to 50 to 100 times less memory than in a standard Python dict at comparable raw lookup speed, with fast prefix search on top. The package is a Cython binding, and it ships a documented list of limitations you should read before adopting it.

**pytries/marisa-trie** — Static memory-efficient Trie-like structures for Python based on marisa-trie C++ library.

- Repository: https://github.com/pytries/marisa-trie
- Website: https://marisa-trie.readthedocs.io/en/latest/
- Stars: 1,125 · Forks: 98
- Language: Cython
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/pytries-marisa-trie

## The argument is memory, not speed

The README states the pitch in numbers. String data in a MARISA trie may take up to 50 to 100 times less memory than in a standard Python dict, the raw lookup speed is comparable, and the trie also provides fast advanced methods like prefix search. That is an unusual positioning for a data structure library, because most of them compete on speed, and this one competes on what a Python process costs you to hold a large vocabulary, a stop word list, a set of identifiers or a prefix index. The package itself is described as static memory-efficient Trie-like structures for Python 3.9 and later, based on the marisa-trie C++ library, and it is a wrapper rather than an implementation, with the underlying library by s-yata. There is a note about alternatives, since the C++ library distribution already includes official SWIG-based Python bindings and this package provides alternative Cython-based bindings that can be installed with pip.

## StringTrie is two tries and an id table

The usage section is short because the structures are close substitutes for a mapping. For immutable str to str mappings, the documentation points at marisa_trie.StringTrie, and it explains the internal shape, that it is implemented as two internal tries plus a compact ID mapping table. That construction is the design in one sentence. One trie holds the keys, another holds the values, and the table maps between them, which is how a string to string mapping is expressed without storing every key and every value twice. The other structures in the package are BytesTrie and RecordTrie, both of which appear in the limitations section with their own method sets, and the tutorial and API pages on the readthedocs site are the place to see how they differ. The key word to carry is immutable. These are static structures, built once and then read, which is the assumption behind the memory figures.

## The limitations section is unusually specific

Most packages bury their rough edges. This one puts them in the README under a heading called Current limitations, and they are worth reading in order. The library is not tested with the mingw32 compiler, which matters if you build from source on Windows. The prefixes() method of BytesTrie and RecordTrie is quite slow and has no iterator counterpart. The read() and write() methods do not work with file-like objects, they work only with real files, although pickling does work for file-like objects. And Trie, BytesTrie and RecordTrie provide keys() and items() methods but no values() method, which is a sharp edge for anyone writing generic code over a mapping. None of these are fatal, but the missing values() and the file-like restriction are the two that will surprise a Python developer who assumes a dict-like interface.

## Installing and reaching for the tutorial

Installation is a pip command, and the documentation is hosted on readthedocs with separate pages for the tutorial and the API.

```bash
python -m pip install -U marisa-trie
```

The package publishes on PyPI as marisa-trie, with a status badge and a list of supported Python versions, and the repository carries a continuous integration workflow for the tests. The repository layout gives the shape of the work, with src/ holding the Cython sources, a marisa-trie/ directory that holds the bundled C++ library, tests/ and tests around the binding, bench/ for the benchmarks, docs/ for the documentation, examples/ with a build_string_trie.py script, and a .well-known/ directory. There is also a LICENSE file, a CHANGES.rst for the release history and AUTHORS.rst, and the readme itself is assembled from README.rst and CHANGES.rst, which is why the change log appears in the project description on PyPI.

## The build compiles the C++ library alongside the Cython layer

The setup.py is where the packaging design becomes clear. There is a Cython extension built from src/*.pyx with language_level set to 3 and a compiler directive marking it as freethreading_compatible, and it links against a libmarisa-trie extension whose sources are the C++ files under the bundled marisa-trie/lib tree, with the grimoire, io, trie and vector subdirectories listed explicitly. The bundled library arrives as a git submodule, which is why the .gitmodules file is in the tree, and the include directory is passed alongside the source directory so the C++ headers are found. The pyproject file asks for setuptools 77 or later and Cython 3.1.3 or later at build time, and it is the modern build metadata that ends up on PyPI, while setup.py remains for the extension definitions. The declared version in the manifest is 1.4.2-dev, which tells you the released version is ahead of the tree.

## Two licences, and the one you have to think about

The licence section is split, and so is the metadata. The wrapper code is licensed under the MIT licence, and the bundled marisa-trie C++ library is dual licensed under LGPL or the BSD 2-clause licence. The pyproject file expresses that as a compound expression, MIT AND (BSD-2-Clause OR LGPL-2.1-or-later), and the license-files list points at four files, AUTHORS.rst and LICENSE in the wrapper and the AUTHORS and COPYING.md inside the bundled library, which is the convention for a project that ships several third-party licence texts and needs to detect when one of them changes. For an organisation shipping this inside a product, the practical question is which of the two branches of the C++ licence you comply with, since the choice is yours and it is recorded in the distribution you publish rather than in the wrapper.

## Beta status, wide Python support, recent releases

The project classifies itself as Development Status 4, Beta, and its audience is listed as developers and science and research users. The topic list is a good summary of the compatibility surface, with pypy3 in it alongside tags for python39 through python314, and the classifiers confirm the range from Python 3.9 to 3.14 plus a beta marker for free threaded builds, which matches the freethreading_compatible compiler directive in the build. The release history is steady, with 1.3.1 on 2025-08-26, 1.4.0 on 2026-03-10 and 1.4.1 on 2026-04-08, and the last push to the default branch was on 2026-07-20, so the repository is not archived and work continues. The gap between a 1.3 line and a 1.4 line is where a behavioural change would live, so an adopter upgrading should read CHANGES.rst in the tree rather than assume a patch release is safe.

## Conclusion

marisa-trie fits a Python program that holds a large, fixed set of strings and is running out of memory with a dict, since a static trie is the structure that answers prefix queries and costs a fraction of the memory, and it fits a team that needs the same lookup behaviour in C and Python. It does not fit an application with a changing key set, since the structures are static by design, and it does not fit a project that needs a values() method or file-like object support in read and write, because the documentation lists both as current limitations. Verify three things first: the memory saving on your own data rather than the factor in the README, whether the operations you need are among the ones the limitations section rules out, and which of the two licences the bundled C++ library will be distributed under, since the wrapper is MIT and the library is dual licensed.

## FAQ

### What is marisa-trie?

It is a package providing static, memory-efficient Trie-like structures for Python 3.9 and later, based on the marisa-trie C++ library. String data in a MARISA trie may take up to 50 to 100 times less memory than in a standard Python dict, with comparable raw lookup speed and fast prefix search.

### How do I install marisa-trie?

Run python -m pip install -U marisa-trie. The package is published on PyPI as marisa-trie, and the tutorial and API reference are on the readthedocs site for the project.

### What are the current limitations of marisa-trie?

The README lists four: the library is not tested with the mingw32 compiler, the prefixes() method of BytesTrie and RecordTrie is quite slow and has no iterator counterpart, read() and write() do not work with file-like objects although pickling does, and Trie, BytesTrie and RecordTrie provide keys() and items() but no values() method.

### How is marisa-trie licensed?

The wrapper code is under the MIT licence, while the bundled marisa-trie C++ library is dual licensed under LGPL or the BSD 2-clause licence. The project metadata records this as MIT AND (BSD-2-Clause OR LGPL-2.1-or-later), with the licence files for both the wrapper and the bundled library.

## Sources

- [License: MIT](https://github.com/pytries/marisa-trie/blob/master/LICENSE)
- [Project website](https://marisa-trie.readthedocs.io/en/latest/)
- [pytries/marisa-trie on GitHub](https://github.com/pytries/marisa-trie)
- [README](https://github.com/pytries/marisa-trie/blob/master/README.md)
- [Releases](https://github.com/pytries/marisa-trie/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pytries-marisa-trie
