Skip to content

The races' numbers

Generated 2026-10-10 from bench/results-race/ by bench/race_svg.py, on Neoverse-N2 (aarch64), Linux. Each library decodes the same token 100,000 times, in 3 rounds, after 1,000 untimed decodes; the time is the mean over all three.

HS256, a 64-byte secret

library 100,000 decodes µs per decode range over 3 rounds vs PyJWT
ryjwt → Struct (Python) 0.21 s 2.08 2.06 to 2.08 28.6x
ryjwt → dict (msgspec) (Python) 0.22 s 2.18 2.18 to 2.19 27.2x
ryjwt → dict (jiter) (Python) 0.26 s 2.60 2.59 to 2.60 22.8x
jsonwebtoken → struct (Rust) 0.38 s 3.83 3.83 to 3.83 15.5x
ryjwt → BaseModel (Python) 0.44 s 4.38 4.37 to 4.39 13.5x
jsonwebtoken → Value (Rust) 0.47 s 4.71 4.70 to 4.72 12.6x
fast-jwt (Bun) 0.69 s 6.85 6.35 to 7.83 8.7x
joserfc (Python) 2.81 s 28.14 28.12 to 28.18 2.1x
jose (Bun) 3.94 s 39.44 38.76 to 40.10 1.5x
PyJWT (Python) 5.93 s 59.31 59.27 to 59.36 1.0x

RS256, a 3072-bit RSA PEM public key

library 100,000 decodes µs per decode range over 3 rounds vs PyJWT
fast-jwt (Bun) 4.85 s 48.46 47.97 to 49.41 2.4x
ryjwt → Struct (Python) 7.04 s 70.39 70.33 to 70.45 1.7x
ryjwt → dict (msgspec) (Python) 7.04 s 70.43 70.37 to 70.49 1.7x
ryjwt → dict (jiter) (Python) 7.09 s 70.89 70.88 to 70.93 1.6x
ryjwt → BaseModel (Python) 7.30 s 73.03 73.03 to 73.04 1.6x
joserfc (Python) 7.60 s 76.04 75.89 to 76.20 1.5x
jsonwebtoken → struct (Rust) 7.72 s 77.18 77.11 to 77.21 1.5x
jsonwebtoken → Value (Rust) 7.79 s 77.92 77.85 to 77.99 1.5x
jose (Bun) 8.03 s 80.34 79.76 to 81.36 1.4x
PyJWT (Python) 11.64 s 116.41 116.38 to 116.45 1.0x