Engine compiled from Google's libphonenumber source at
github.com/google/libphonenumber@6e46509.
Corpus: 1,132 phone numbers, one Google example per region per type (the example set the conformance
corpus is derived from).
Compared against the npm packages
libphonenumber-js@1.13.3
and
google-libphonenumber@3.2.44
(a community wrapper around Google's libphonenumber JS source).
Generated 2026-07-21T18:06:32.366Z.
Parse cost only.
| Operation | Telixon (ops/s) | libphonenumber-js (ops/s) | google-libphonenumber (ops/s) | vs libphonenumber-js | vs google-libphonenumber |
|---|---|---|---|---|---|
parsePhoneNumber (corpus pass) | 774 | 150 | 176 | 5.16× | 4.39× |
Parse + one method call. Telixon module caches cleared per iteration.
| Method | Telixon (ops/s) | libphonenumber-js (ops/s) | google-libphonenumber (ops/s) | vs libphonenumber-js | vs google-libphonenumber |
|---|---|---|---|---|---|
isValid | 562 | 123 | 94 | 4.57× | 5.98× |
isPossible | 489 | 136 | 168 | 3.60× | 2.90× |
isPossibleWithReason | 526 | 64 | 167 | 8.21× | 3.16× |
getNumberType | 564 | 107 | 91 | 5.26× | 6.20× |
getNationalNumber | 693 | 136 | 173 | 5.08× | 4.01× |
getCallingCode | 679 | 145 | 175 | 4.68× | 3.88× |
getRegion | 618 | 144 | 144 | 4.30× | 4.29× |
formatE164 | 507 | 145 | 165 | 3.50× | 3.07× |
formatRfc3966 | 317 | 133 | 101 | 2.39× | 3.13× |
formatNational | 304 | 94 | 107 | 3.22× | 2.85× |
formatInternational | 323 | 90 | 112 | 3.60× | 2.89× |
Parse + one method call. Caches retained across iterations.
| Method | Telixon (ops/s) | libphonenumber-js (ops/s) | google-libphonenumber (ops/s) | vs libphonenumber-js | vs google-libphonenumber |
|---|---|---|---|---|---|
isValid | 585 | 118 | 96 | 4.94× | 6.11× |
isPossible | 526 | 134 | 167 | 3.91× | 3.16× |
isPossibleWithReason | 538 | 66 | 167 | 8.19× | 3.23× |
getNumberType | 583 | 114 | 95 | 5.11× | 6.14× |
getNationalNumber | 704 | 145 | 176 | 4.86× | 4.01× |
getCallingCode | 700 | 145 | 176 | 4.82× | 3.98× |
getRegion | 615 | 146 | 144 | 4.22× | 4.27× |
formatE164 | 512 | 145 | 170 | 3.54× | 3.02× |
formatRfc3966 | 338 | 135 | 103 | 2.50× | 3.28× |
formatNational | 348 | 94 | 107 | 3.68× | 3.24× |
formatInternational | 389 | 90 | 113 | 4.34× | 3.43× |
Pre-parsed value, method called repeatedly. Where libphonenumber-js stores the value as a direct property after
parse (nationalNumber, countryCallingCode, number, country),
a property read is 1-4% faster than Telixon's cached method call.
| Method | Telixon (ops/s) | libphonenumber-js (ops/s) | google-libphonenumber (ops/s) | vs libphonenumber-js | vs google-libphonenumber |
|---|---|---|---|---|---|
isValid | 30.5k | 684 | 220 | 44.66× | 138.87× |
isPossible | 30.5k | 2.2k | 4.3k | 13.83× | 7.05× |
isPossibleWithReason | 29.2k | 115 | 4.0k | 254.06× | 7.27× |
getNumberType | 33.0k | 597 | 219 | 55.20× | 150.19× |
getNationalNumber | 33.4k | 33.6k | 20.7k | 0.99× | 1.61× |
getCallingCode | 34.1k | 34.0k | 23.9k | 1.00× | 1.43× |
getRegion | 34.7k | 34.1k | 830 | 1.02× | 41.77× |
formatE164 | 34.5k | 35.5k | 10.0k | 0.97× | 3.44× |
formatRfc3966 | 29.9k | 2.3k | 248 | 13.06× | 120.54× |
formatNational | 27.9k | 289 | 283 | 96.32× | 98.59× |
formatInternational | 28.1k | 247 | 322 | 113.46× | 87.04× |
Telixon only: competitor formatters have no comparable API (no caret, no deletion, no undo, no per-keystroke queries). One iteration is a full corpus pass: every digit of all 1,132 corpus numbers, typed end to end through the controller. Read the mean column as "what typing the entire corpus costs"; single keystrokes are profiled in the next section.
| Scenario | ops/s | mean (ms) | p99 (ms) | ±rme |
|---|---|---|---|---|
| type-through full number (corpus pass) | 33 | 30.51 | 33.70 | ±2.02% |
| type-through + core PhoneNumber query methods per keystroke (corpus pass) | 14 | 69.38 | 70.86 | ±0.79% |
| backspace at caret after full type-through (corpus pass) | 16 | 60.73 | 63.11 | ±1.08% |
| type-through + undo + redo (corpus pass) | 32 | 30.92 | 32.32 | ±1.27% |
| full undo back to empty + redo to full (corpus pass) | 32 | 31.66 | 33.83 | ±1.70% |
The number that decides whether an input feels instant: the cost of one keystroke, sampled individually (process.hrtime.bigint()
after warmup). For scale, the panel below measures that latency against one display frame across common refresh
rates (60-360 Hz); the benchmark itself runs headless, so it assumes no single display.
| Scenario | samples | mean | p50 | p95 | p99 |
|---|---|---|---|---|---|
| international: insert per keystroke | 68,720 | 1.26 µs | 1.24 µs | 2.19 µs | 3.33 µs |
| international: insert + 7 query methods per keystroke | 68,720 | 2.15 µs | 1.95 µs | 3.91 µs | 6.93 µs |
Worst-case (p99) keystroke against one frame, at common display refresh rates:
| Display refresh rate | One frame | p99 keystroke headroom |
|---|---|---|
| 60 Hz | 16.67 ms | 2,405× |
| 120 Hz | 8.33 ms | 1,202× |
| 240 Hz | 4.17 ms | 601× |
| 360 Hz (strictest) | 2.78 ms | 401× |
Across 137,440 sampled keystrokes, the 99th percentile is 6.93 µs. The maximum and deep tail are omitted: they are dominated by OS scheduling, not the code, and grow with sample count.
Phone-number processing alone stays orders of magnitude under one frame at every standard refresh rate.