Skip to content

Performance ​

Sentinel Password is designed to be fast and lightweight. This page covers benchmark results, bundle size comparisons, and performance tips.

Bundle Size ​

One of the key advantages of Sentinel Password is its minimal footprint:

PackageESMESM (gzip)CJS (gzip)
@sentinel-password/core18.4 KB6.3 KB6.5 KB
@sentinel-password/react2.5 KB0.7 KB—
@sentinel-password/react-components6.0 KB1.7 KB—

Comparison with Alternatives ​

LibraryGzipped SizeDependenciesNotes
@sentinel-password/core6.3 KB0Bloom filter, 7 validators, O(1) common password lookup
zxcvbn~400 KB0Large frequency-ranked dictionaries
password-validator~4 KB0Basic rule-based validation
check-password-strength~1 KB0Regex-only strength scoring

Sentinel Password delivers comprehensive validation — including common password detection via bloom filter, keyboard pattern analysis, and sequential character detection — at a fraction of zxcvbn's bundle cost.

Benchmark Results ​

Benchmarks were run using Vitest bench on a single core. All numbers are operations per second (higher is better).

Validation Speed ​

Password Typesentinel-passwordzxcvbncheck-password-strengthpassword-validator
Weak ("password")1,410,000 ops/s22,000 ops/s2,902,000 ops/s1,290,000 ops/s
Medium ("MyPassword1")1,741,000 ops/s6,500 ops/s2,348,000 ops/s1,732,000 ops/s
Strong ("MyP@ssw0rd123!")2,221,000 ops/s2,700 ops/s2,275,000 ops/s2,063,000 ops/s
Long (200+ chars)319,000 ops/s8 ops/s2,185,000 ops/s1,238,000 ops/s
Batch (100 passwords)18,000 batches/s56 batches/s24,000 batches/s16,000 batches/s

How to Read These Numbers ​

  • vs. zxcvbn: Sentinel Password is 60–40,000x faster depending on password length. zxcvbn's entropy-based pattern matching is thorough but computationally expensive, especially on long inputs where it degrades to single-digit ops/sec.
  • vs. check-password-strength: It's faster because it only runs basic regex checks — no dictionary, no keyboard patterns, no sequential detection. The speed difference reflects the difference in validation depth.
  • vs. password-validator: Similar scope but uses a fluent API with simple regex rules. Faster for the same reason — fewer checks.

Key Takeaway

Sentinel Password validates a typical password in well under a microsecond (~0.6 µs). For comparison, a single DOM repaint takes ~16 milliseconds — over 20,000x longer. Password validation will never be your bottleneck.

Individual Validator Performance ​

Validatorops/secTime per call
Length30,000,000~33 ns
Repetition22,660,000~44 ns
Character types16,570,000~60 ns
Common password (bloom filter)11,090,000~90 ns
Sequential9,170,000~109 ns
Personal info8,340,000~120 ns
Keyboard patterns6,150,000~163 ns

All seven validators run in tens to hundreds of nanoseconds. The full validatePassword pipeline is dominated by per-call function-call overhead rather than any single validator.

Historical note

The keyboard pattern validator used to be ~250× slower than the others (~117,000 ops/s) because it rebuilt each pattern's reversed string via split('').reverse().join('') on every invocation across the ~80 multi-layout patterns. As of 2026-05-14 it uses a single precomputed regex with all 160 forward+reverse alternatives, which is ~50× faster. See packages/core/tests/performance.bench.ts → "Keyboard pattern impl comparison" for the side-by-side benchmark of the three implementations explored.

Entropy Estimation Performance ​

@sentinel-password/entropy is an optional standalone package that adds Shannon entropy + crack-time estimation alongside core's rule-based validation. Install it only if you need a "how long would this survive a brute-force attack?" signal.

Latency by Password Shape ​

Fixtureops/secTime per call
Dictionary hit ("password")835,000~1.2 μs
Repetition ("aaaaaaaa")918,000~1.1 μs
Keyboard pattern ("qwertyuiop")737,000~1.4 μs
Passphrase ("correct horse battery staple")74,000~13 μs
Long edge case (256 chars)42,000~24 μs
L33t + capitalization ("Tr0ub4dor&3")33,000~31 μs
Pure-random 12-char24,000~41 μs

Fast paths (dictionary hits, repetitions, keyboard patterns) exit early via specific detectors. Slower fixtures exercise the full substring-scan plus l33t-candidate enumeration paths.

sentinel-entropy vs zxcvbn ​

The only meaningful entropy comparator is zxcvbn — both libraries produce entropy bits + a 0-4 score + crack-time estimates under multiple attacker models.

Password Typesentinel-entropyzxcvbnSpeedup
Weak ("password")817,000 ops/s21,500 ops/s38×
Medium ("MyPassword1")135,000 ops/s5,400 ops/s25×
Strong ("MyP@ssw0rd123!")63,000 ops/s2,400 ops/s26×
Long (200+ chars)14,300 ops/s5.2 ops/s2,766×
Batch (100 passwords)1,150 batches/s36 batches/s32×

The gap widens dramatically on long inputs — zxcvbn's dictionary partition search scales superlinearly with length, while sentinel-entropy's greedy walk caps each dictionary probe at 18 chars.

Trade-off

sentinel-entropy is intentionally simpler than zxcvbn. It skips the dynamic-programming partition search to stay under the 30 KB bundle budget (zxcvbn ships ~400 KB). Accuracy on adversarial inputs is somewhat lower; runtime and bundle cost are dramatically better.

Run Environment ​

The numbers above were captured on:

  • CPU: Apple M4 (10 cores)
  • OS: macOS (Darwin 25.5.0, arm64)
  • Node: v26.0.0
  • Vitest: ^4.1.8

Ops/sec varies 30-50 % across hardware (Intel/AMD/ARM, laptop/desktop/CI runner). Treat absolute values as illustrative; relative ranking (which library is fastest, by what factor) is stable across machines.

Performance Tips ​

Use Debouncing in React ​

The React hook includes built-in debouncing (300ms default) to avoid validating on every keystroke:

typescript
import { usePasswordValidator } from '@sentinel-password/react'

const { password, setPassword, result } = usePasswordValidator({
  minLength: 8,
  debounceMs: 300, // Default — validates 300ms after typing stops
})

Disable Checks You Don't Need ​

validatePassword always invokes all seven built-in validators — there is no way to skip a validator entirely from the top-level call. Three of them, however, have explicit disable flags that short-circuit the validator's inner work via an early-return:

typescript
import { validatePassword } from '@sentinel-password/core'

const result = validatePassword(password, {
  checkCommonPasswords: false,    // skips Bloom-filter lookup
  checkKeyboardPatterns: false,   // skips QWERTY/AZERTY scan
  checkSequential: false,         // skips abc/123 scan
})
// `length`, `characterTypes`, `repetition`, and `personalInfo` still run.

Two notes on what this actually does:

  • The disabled validators are still called and still appear in result.checks — they just always report passed: true when their flag is off. Don't treat result.checks.sequential === true as proof the password was checked for sequences if you've disabled the flag.
  • The other four validators have no disable flag. To make them effectively no-ops:
    • length — set minLength: 0, maxLength: 9999. (Use 0, not 1 — validateLength rejects with strict length < minLength, so minLength: 1 still fails empty strings.)
    • repetition — set maxRepeatedChars: 9999.
    • characterTypes — leave the require* flags off (the default).
    • personalInfo — omit the personalInfo array (the default; the validator early-returns on empty arrays).

The savings are real but small — validation already runs in microseconds end-to-end (see the Individual Validator Performance table). If you genuinely need only one or two checks, prefer the tree-shaking pattern below.

Tree-Shaking Individual Validators ​

If you only need specific validators, import them directly. Bundlers will tree-shake the rest:

typescript
import { validateLength, validateCharacterTypes } from '@sentinel-password/core'

const lengthCheck = validateLength(password, { minLength: 12 })
// { passed: true | false, message?: string }

const charCheck = validateCharacterTypes(password, {
  requireUppercase: true,
  requireDigit: true,
})

Running Benchmarks Locally ​

To reproduce these benchmarks on your machine:

bash
git clone https://github.com/akankov/sentinel-password.git
cd sentinel-password
pnpm install

# Run all packages' benchmarks (core + entropy)
pnpm bench

# Or scope to a single package
pnpm --filter @sentinel-password/core bench
pnpm --filter @sentinel-password/entropy bench

Each package has two suites: performance.bench.ts (internal latency) and comparative.bench.ts (vs competitor libraries).

Released under the MIT License.