tokie
Library Listed
Blazingly fast tokenizer - 50x faster tokenization, 10x smaller model files, 100% accurate drop-in replacement for HuggingFace
- Downloads
- 711
- Dependents
- 3
- Stars
- 56
- Forks
- 6
- Contributors
- 3
- Commits
- 243
- Latest release
- 0.1.4 ·
About

25 to 150 times faster than Hugging Face tokenizers, with the same token ids
Install • Quick start • Examples • Benchmarks • Why tokie?
[!CAUTION] tokie is in its alpha stage and might produce mis-aligned output. Please report any issues you encounter.
tokie is a Rust tokenizer library with Python bindings. It loads a Hugging Face tokenizer.json and encodes 25 to 150 times faster than Hugging Face tokenizers. It implements BPE, WordPiece, SentencePiece, and Unigram. The token ids match Hugging Face tokenizers.

Install
Python
pip install tokie
Rust
[dependencies]
tokie = "0.2"
This tree is 0.2. crates.io and PyPI still serve 0.1.4, which does not have these calls.
Coming from Hugging Face tokenizers? See the migration guide.
Read the full README
Quick start
Python
import tokie
tokenizer = tokie.Tokenizer.from_pretrained("google-bert/bert-base-uncased")
ids = tokenizer.encode("Hello, world!")
print(ids.tolist())
plus = tokenizer.encode_plus("Hello, world!")
print(plus.tolist())
print(tokenizer.encode_plus("Hello", pair="world", truncate=True, pad=True, max_len=8).tolist())
print(tokenizer.decode(plus.tolist(), skip=True))
flat, ends = tokenizer.batch(["Hello!", "World"])
print(tokenizer.count_tokens("Hello, world!"))
print(tokenizer.count_tokens_batch(["Hello!", "World"]))
encode returns a uint32 array and leaves the template off. encode_plus writes the single-sequence template, so BERT uncased is [CLS], the ids, [SEP]. pair uses the pair template. truncate and pad share max_len, and that length counts the template ids. batch returns one id array and ends[i], the id count after text i. count_tokens returns the length encode would append. count_tokens_batch returns one length per text. Both leave the template off.
Rust
use tokie::{Plus, Specials, Tokenizer};
let mut tokenizer = Tokenizer::pretrained("google-bert/bert-base-uncased")?;
let mut ids = Vec::new();
tokenizer.encode("Hello, world!", &mut ids)?;
ids.clear();
tokenizer.encode_plus("Hello, world!", &mut ids)?;
tokenizer.encode_plus(Plus::new("Hello").pair("world").truncate(8).pad(8), &mut ids)?;
let mut text = String::new();
tokenizer.decode(&ids, &mut text, Specials::Skip)?;
let n = tokenizer.count_tokens("Hello, world!")?;
let lengths = tokenizer.count_tokens_batch(&["Hello!", "World"])?;
encode and encode_plus append into the Vec the caller owns. Clear it to start a new sequence. count_tokens and count_tokens_batch write ids into a buffer on the tokenizer and return the lengths. They leave the template off.
Examples
Batch
tokenizer.threads(4)
flat, ends = tokenizer.batch(["Short text", "A much longer piece of text"])
tokenizer.threads(4);
let lines = ["Short text", "A much longer piece of text"];
let mut ids = Vec::new();
let mut ends = Vec::new();
tokenizer.batch(&lines, &mut ids, &mut ends)?;
Text i is ids[prev..ends[i]]. ends[i] is ids.len() after that text.
Vocabulary
tokenizer.id("[SEP]")
tokenizer.token(101)
tokenizer.id("[SEP]");
tokenizer.token(101);
Save and load a .tokie file
tokenizer.save("model.tokie")
again = tokie.Tokenizer.open("model.tokie")
tokenizer.save("model.tokie")?;
let mut again = Tokenizer::open("model.tokie")?;
from_pretrained in Python, and pretrained in Rust, reads the repo's .tokie file and then tokenizer.json.
Benchmarks
All benchmarks run on an Apple M3 with tokie 0.1.3. The ids match Hugging Face tokenizers.
BPE encoding (GPT-2, Llama, Qwen, ModernBERT)
For tiktoken-style BPE, tokie uses a backtracking encoder on an Aho-Corasick automaton. It takes a greedy longest match in O(n), and it backtracks only when two adjacent tokens are not a valid pair. It does not merge one byte pair at a time. Pretokenization is the SIMD mask scanner in pretokie. That scanner classifies 64-byte blocks into piece-boundary bitmasks and runs above 1 GB/s per core. A repeated piece hits a per-worker cache instead of running BPE again. Work stealing splits the text so every core has a chunk. On one string this is 39 to 154 times faster than Hugging Face tokenizers.

WordPiece (BERT, MiniLM, BGE, GTE)
WordPiece searches a vocabulary trie for the longest prefix. tokie stores that trie as a Double-Array trie and looks it up in O(n), with a BERT pretokenizer. On BERT this is 25 to 71 times faster than Hugging Face tokenizers, and the ids match.

SentencePiece BPE and Unigram (Gemma, XLM-R, T5)
SentencePiece BPE merges in an order that is not topological. tokie uses a radix heap. Insert and pop are O(1) amortized because a later BPE rank is never smaller. On Gemma 3 this is 2 to 3 times faster than Hugging Face tokenizers.
Unigram models such as T5, XLM-RoBERTa, and ALBERT run Viterbi on each metaspace-delimited word and store the frequent units. Encoding one string is about 4 times faster than whole-string Viterbi. Batch encoding is about 3 times faster. The ids match. A vocabulary with a metaspace inside a token uses whole-string Viterbi.


Python benchmarks
All results on Apple M3, single-string encode, median of 10 runs.
tokie vs Hugging Face tokenizers
| Model | Text size | tokie | Hugging Face | Speedup |
|---|---|---|---|---|
| BERT | 45 KB | 0.38 ms | 9.6 ms | 25x |
| BERT | 900 KB | 3.60 ms | 257 ms | 71x |
| GPT-2 | 45 KB | 0.13 ms | 8.6 ms | 65x |
| GPT-2 | 900 KB | 1.44 ms | 191 ms | 133x |
| Llama 3 | 45 KB | 0.22 ms | 8.6 ms | 39x |
| Llama 3 | 900 KB | 2.49 ms | 195 ms | 78x |
| Qwen 3 | 45 KB | 0.13 ms | 9.1 ms | 68x |
| Qwen 3 | 900 KB | 1.36 ms | 210 ms | 154x |
| ModernBERT | 45 KB | 0.15 ms | 9.3 ms | 62x |
| ModernBERT | 900 KB | 1.42 ms | 211 ms | 149x |
| Gemma 3 | 45 KB | 4.54 ms | 9.7 ms | 2x |
| Gemma 3 | 900 KB | 114 ms | 289 ms | 3x |
tokie vs tiktoken (OpenAI models)
| Model | Text size | tokie | tiktoken | Speedup |
|---|---|---|---|---|
| cl100k (GPT-4) | 45 KB | 0.13 ms | 2.12 ms | 17x |
| cl100k (GPT-4) | 900 KB | 1.28 ms | 42.3 ms | 33x |
| o200k (GPT-4o) | 45 KB | 0.16 ms | 3.57 ms | 22x |
| o200k (GPT-4o) | 900 KB | 1.66 ms | 70.7 ms | 42x |
The ids match on every model in these tables. Batch encoding is 17 to 36 times faster than Hugging Face tokenizers. encode_batch_flat returns one contiguous NumPy array.
Tokenizer loading
Loading tokenizer.json parses the JSON, builds the vocabulary, and, for BPE, builds the Aho-Corasick automaton. tiktoken parses its BPE data and compiles its regexes on every load. A .tkz file stores the Double-Array Aho-Corasick state, the normalized vocabulary, the encoder configuration, and, since v13, the added and special tokens. Loading that file is deserialization. from_pretrained reads the hub disk cache before the network and writes the compiled .tkz next to the snapshot, so a warm load does not use the network. A warm load is 13 to 44 times faster than Hugging Face tokenizers. BERT takes 2.8 ms. GPT-2 takes 6.2 ms.
| Model | tokie | Hugging Face | Speedup |
|---|---|---|---|
| BERT | 2.8 ms | 123 ms | 44x |
| GPT-2 | 6.2 ms | 151 ms | 24x |
| Llama 3.2 | 10.6 ms | 261 ms | 25x |
| cl100k | 11.1 ms | 244 ms | 22x |
| o200k | 23.2 ms | 310 ms | 13x |

Verified tokenizers
A passing tokenizer is tested against the Hugging Face tokenizer on 1 MB of enwik8, about 300,000 tokens, in CI. Pass means every token matches. Not supported means tokie 0.2 refuses the file.
The full matrix is in docs/TOKENIZERS.md.
Full accuracy table, 75 models
69 pass. 6 are not supported, out of 75 listed. The passing tokenizers' ids match Hugging Face tokenizers.
Why tokie?
When I started building Chonkie, tokenization took longer than chunking.
Each pretokenization pattern has its own parser: GPT-2, cl100k, o200k, and BERT. The parser uses that pattern's character classes and does not run a general regex engine. Since 0.1.0 those parsers are a SIMD mask scanner. They classify 64-byte blocks into character-class bitmasks and take piece boundaries from the masks. Pretokenization passes 1 GB/s per core, more than 20 times the reference regexes.
No single library loaded every Hugging Face tokenizer. I tried AutoTikTokenizer and expected tiktoken's BPE to cover them. It does not. Tiktoken-style models need backtracking BPE. A merge order that is not topological needs a heap. SentencePiece needs a radix heap. WordPiece and Unigram each need their own encoder.
Tokenization runs in parallel when the split keeps token boundaries. chunk splits the text on those boundaries. Each core encodes one chunk, and the ids are concatenated. On 8 cores that is about 5 times faster.
.tkz skips rebuilding those structures at load time. tokenizer.json is parsed and validated, and the Aho-Corasick automaton is built. That build is slow for a large vocabulary. .tkz stores the automaton, the vocabulary, the configuration, and the added tokens as a flat binary. Loading deserializes that file. With the hub cache and a compiled file on disk, a warm BERT load is 2.8 ms and a warm GPT-2 load is 6.2 ms. Hugging Face tokenizers takes 120 to 310 ms on those two models.
Acknowledgements
tokie uses ideas from Hugging Face tokenizers, tiktoken, and GitHub's rust-gems for backtracking BPE via Aho-Corasick. It also uses chunk for SIMD text splitting, and gigatoken. Gigatoken's piece cache, mask-scanner pretokenization, and benchmarks shaped the 0.1.0 hot path.
Citation
If you use tokie in your research, please cite it as follows:
@software{tokie2025,
author = {Minhas, Bhavnick},
title = {tokie: Fast, correct tokenizer library for every Hugging Face model},
year = {2025},
publisher = {GitHub},
howpublished = {\url{https://github.com/chonkie-inc/tokie}},
}
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- Apache-2.0 OR MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Blazingly fast tokenizer - 50x faster tokenization, 10x smaller model files, 100% accurate drop-in replacement for HuggingFace |
711 downloads over 30 days | 3 | 56 | 0.1.4 | GPU support unknown | No native code found | Apache-2.0 OR MIT |
|
whichlang Listed
A blazingly fast and lightweight language detection library for Rust. |
52,880 downloads over 30 days | 11 | 464 | 0.1.1 | GPU support unknown | No native code found | MIT |
|
splintr Listed
Tokenizer for Rust and Python: pure Rust by default, with 18 bundled vocabularies and four backends covering BPE, SentencePiece and WordPiece. Its output matches Hugging Face tokenizers id for id on 14 model families, including GPT-2, Qwen, Whisper, T5 and BERT. Python bindings |
8,204 downloads over 30 days | 7 | 63 | 0.22.2 | GPU support unknown | Binds native code: pcre2-sys (feature pcre2) | MIT |
|
udpipe-rs Listed
Rust bindings for UDPipe - a trainable pipeline for tokenization, tagging, lemmatization and dependency parsing of CoNLL-U files |
3,069 downloads over 30 days | 2 | 5 | 0.2.0 | GPU support unknown | Build uses a native toolchain: cc | Apache-2.0 OR MIT |
|
kitoken Listed
Fast tokenizer for language models, supporting BPE, Unigram and WordPiece tokenization |
2,949 downloads over 30 days | 3 | 62 | 0.11.1 | GPU support unknown | No native code found | BSD-2-Clause |
|
tokenx-rs Listed
Fast token count estimation for LLMs at 96% accuracy without a full tokenizer |
1,235 downloads over 30 days | 3 | 3 | 0.1.0 | GPU support unknown | No native code found | MIT |
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- It has 2 active dependents and 2 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 56 stars, 6 forks and 3 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
What else the check found
- The last activity is on 3 Nov 2026, 6 days ago. The rules expect an update within 450 days. Dormancy rule
Exact rules: Listed, Featured library. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: version 0.1.4 base 450: E = 450 daysdormancy: last activity 2026-11-03, 6 days ago, E = 450: activefeatured: not featured: active_users 2 < 11 and new_adopters 2 < 9 and repository route stars 56 (needs 4539), forks 6 (needs 434), contributors 3 (needs 79)listed: listed: no archive, new or featured rule applies
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the crates.io description
- crates.io database dump, fetched
- RustSec advisory database, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption2 active dependents, 2 new dependents in 365 days1 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | 2 | crates.io database dump | Yes | |
| New dependents (365 days) | 2 | crates.io database dump | Yes | |
| Peak active dependents | 3 | crates.io database dump | Yes | |
| Active dependents as a share of the peak | 1 | crates.io database dump | Yes | |
| Binary downloads per release | Not measured | Yes |
MaintenanceLatest human commit: 6 days ago3 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-03 | GitHub repository | Yes | |
| Latest release | 2026-07-24 | crates.io database dump | Yes | |
| First release | 2026-03-23 | crates.io database dump | Yes | |
| Latest version | 0.1.4 | crates.io database dump | Yes | |
| Days the oldest outside issue waits for a reply | 184 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 1 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | Yes | |
| Published docs | true | crates.io database dump | Yes | |
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityUnpatched vulnerabilities: none
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | none | RustSec advisory database | Yes | |
| RustSec unmaintained advisory | none | RustSec advisory database | Yes | |
| Deprecation notice | none | crates.io database dump | Yes | |
| Deprecated requirement | none | crates.io database dump | Yes |
Distribution17 releases, 711 downloads over 30 days5 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 17 | crates.io database dump | Yes | |
| Downloads over 30 days | 711 | crates.io database dump | Yes | |
| Binary downloads over the last 3 releases | Not measured | Yes | ||
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | false | crates.io database dump | Yes | |
| Crate deleted from crates.io | false | crates.io database dump | Yes |
Repository56 stars, 6 forks, 3 contributors, 243 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 56 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 6 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 3 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 243 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | Apache-2.0 OR MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | 3 | crates.io database dump | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.