npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ts-phonenumber

v2.0.0

Published

TypeScript-first phone-number parsing/formatting/validation library based on Google's libphonenumber

Readme

ts-phonenumber

CI codecov npm version npm downloads bundle size TypeScript node License

The fastest phone number library for JavaScript/TypeScript. Parse, validate, and format phone numbers with blazing speed and tiny bundles.

Features

  • Blazing fast — Up to 11x faster than alternatives (see benchmarks)
  • TypeScript-first — Full type safety with comprehensive type definitions
  • Dual API — Async for lazy loading, sync for maximum performance
  • Tiny bundles — ~5KB core + on-demand metadata via import()
  • Modern runtimes — Node.js 20+, Bun, and modern browsers
  • CLI included — Command-line tool for validation and formatting

Installation

npm install ts-phonenumber
# or
pnpm add ts-phonenumber
# or
yarn add ts-phonenumber

Usage

Synchronous API (Maximum Performance)

For servers, CLIs, and performance-critical code. Pre-load metadata once, then use sync functions:

import { parseSync, validateSync, formatSync, registerMetadata } from "ts-phonenumber"

// Pre-load metadata (do this once at startup)
import DE from "ts-phonenumber/metadata/countries/DE"
registerMetadata(DE)

// Now use sync functions - no async overhead!
const parsed = parseSync("+491701234567")
console.log(parsed.regionCode) // "DE"
console.log(parsed.type) // "mobile"

const isValid = validateSync("+491701234567")
console.log(isValid.isValid) // true

const formatted = formatSync(parsed, "international")
console.log(formatted) // "+49 170 123 4567"

Async API (Lazy Loading)

For web apps where you want to load metadata on-demand:

import { parse, validate, format, getType } from "ts-phonenumber"

// Metadata is loaded automatically when needed
const parsed = await parse("+491701234567")
console.log(parsed)
// {
//   countryCode: 49,
//   nationalNumber: "1701234567",
//   regionCode: "DE",
//   type: "mobile",
//   isValid: true,
//   rawInput: "+491701234567"
// }

// Validate a phone number
const result = await validate("+491701234567")
console.log(result.isValid) // true
console.log(result.type) // "mobile"

// Format a phone number
const e164 = await format("+491701234567", "e164")
console.log(e164) // "+491701234567"

const intl = await format("+491701234567", "international")
console.log(intl) // "+49 170 123 4567"

const national = await format("+491701234567", "national")
console.log(national) // "0170 123 4567"

// Get number type
const type = await getType("+491701234567")
console.log(type) // "mobile"

Parsing National Numbers

When parsing numbers without a country code, provide a default region:

import { parse } from "ts-phonenumber"

const parsed = await parse("0170 1234567", { defaultRegion: "DE" })
console.log(parsed.countryCode) // 49
console.log(parsed.nationalNumber) // "1701234567"

Loading Metadata

Metadata is loaded on-demand when you first use a region. You can also preload metadata:

import { loadRegionMetadata, preloadRegions, loadMetadataBundle } from "ts-phonenumber"

// Load a single region
await loadRegionMetadata("DE")

// Preload multiple regions
await preloadRegions(["DE", "AT", "CH"])

// Load a group bundle (loads all regions in the group)
await loadMetadataBundle("DACH")

Type Checking

import { isMobile, isLandline, isVoIP } from "ts-phonenumber"

console.log(await isMobile("+491701234567")) // true
console.log(await isLandline("+493012345678")) // true
console.log(await isVoIP("+493212345678901")) // true

CLI Usage

The package includes a CLI for quick validation and formatting:

# Validate a number
ts-phonenumber validate "+491701234567"
ts-phonenumber validate "0170 1234567" --region DE

# Parse and show details
ts-phonenumber parse "+491701234567"
ts-phonenumber parse "0170 1234567" --region DE --json

# Format a number
ts-phonenumber format "+491701234567" --format e164
ts-phonenumber format "+491701234567" --format international
ts-phonenumber format "+491701234567" --format national
ts-phonenumber format "+491701234567" --format rfc3966

# Get number type
ts-phonenumber type "+491701234567"

Supported Number Types

This library only supports the following number types:

  • "landline" - Fixed-line/geographic numbers
  • "mobile" - Mobile phone numbers
  • "voip" - Voice over IP numbers

All other types (toll-free, premium rate, shared cost, etc.) are treated as "invalid".

Scope & Testing Transparency

Why This Library?

Google's libphonenumber is the industry standard, but it comes with trade-offs:

| Aspect | libphonenumber | ts-phonenumber | | --------------- | ------------------------------ | --------------------------------- | | Performance | Baseline | 5-11x faster (see benchmarks) | | Language | Java (with JS port) | TypeScript-native | | Bundle size | ~200-300KB (all metadata) | ~5KB core + on-demand metadata | | Number types | All (toll-free, premium, etc.) | Only LANDLINE, MOBILE, VOIP | | API style | Synchronous only | Dual: async + sync | | Runtime | Any | Node 20+, Bun, modern browsers |

Our focus: Most applications only need to validate user-provided phone numbers (mobile/landline). By excluding special service numbers, we keep bundles small, validation strict, and performance blazing fast.

Test Coverage

We validate our implementation against Google's original test suite:

| Source | Original Tests | Converted | Coverage | | ---------------------------- | -------------- | --------- | ------------ | | phonenumberutil_test.js | 111 | 96 | 86% | | asyoutypeformatter_test.js | 33 | 0 | Not in scope | | Total | 144 | 129 | 90% |

Skipped tests (5) are explicitly marked with reasons:

  • Toll-free number formatting (not in scope)
  • Premium rate number formatting (not in scope)
  • Complex edge cases (documented individually)

What We Explicitly Don't Support

| Feature | Reason | | -------------------------------------- | ----------------------------------- | | Toll-free numbers (800, 0800, etc.) | Outside user-input validation scope | | Premium rate numbers (900, 0900, etc.) | Outside user-input validation scope | | Short codes (SMS short numbers) | Outside user-input validation scope | | Shared cost, UAN, Voicemail | Outside user-input validation scope | | AsYouTypeFormatter | Complexity vs. value trade-off | | Legacy runtimes (Node < 20) | Modern tooling requirement |

Numbers of unsupported types will parse successfully but return type: "invalid" and isValid: false.

Metadata Updates

Metadata is derived from Google's libphonenumber and updated via semi-automatic tooling:

pnpm upstream:update  # Check for updates, convert, test

The current upstream version is tracked in upstream/.version.

Metadata Bundles

Metadata is organized into individual country modules and group bundles:

Individual Countries

import DE from "ts-phonenumber/metadata/countries/DE"
import US from "ts-phonenumber/metadata/countries/US"

Group Bundles

import DACH from "ts-phonenumber/metadata/bundles/DACH" // DE, AT, CH

API Reference

Types

  • PhoneNumberType - "landline" | "mobile" | "voip" | "invalid"
  • PhoneNumberFormat - "e164" | "international" | "national" | "rfc3966"
  • ParsedPhoneNumber - Result of parsing a phone number
  • ValidationResult - Result of validating a phone number
  • ParseOptions - Options for parsing (includes defaultRegion)

Async Functions

  • parse(input, options?) - Parse a phone number string
  • validate(input, options?) - Validate a phone number
  • isValidNumber(input, options?) - Simple boolean validation
  • format(input, format, options?) - Format a phone number
  • getType(input, options?) - Get the phone number type
  • isMobile(input, options?) - Check if number is mobile
  • isLandline(input, options?) - Check if number is landline
  • isVoIP(input, options?) - Check if number is VoIP

Sync Functions (Maximum Performance)

  • parseSync(input, options?) - Parse a phone number (requires pre-loaded metadata)
  • validateSync(input, options?) - Validate a phone number
  • isValidNumberSync(input, options?) - Simple boolean validation
  • formatSync(input, format, options?) - Format a phone number

Metadata Functions

  • registerMetadata(metadata) - Register metadata for sync API
  • loadRegionMetadata(regionCode) - Load metadata for a region (async)
  • loadMetadataBundle(bundleName) - Load a group bundle (async)
  • preloadRegions(regionCodes) - Preload multiple regions (async)
  • isMetadataLoaded(regionCode) - Check if metadata is loaded
  • clearMetadataCache() - Clear the metadata cache

Benchmarks

Up to 11x faster than alternatives — ts-phonenumber wins all 7 benchmarks against the most popular phone number libraries.

| Benchmark | ts-phonenumber | vs libphonenumber-js | vs google-libphonenumber | vs awesome-phonenumber | | --------------- | -------------: | :--------------------: | :------------------------: | :----------------------: | | Parse E.164 | 1.56M/s | 3.3x faster | 4.9x faster | 25x faster | | Parse national | 2.14M/s | 6.4x faster | 9.9x faster | 37x faster | | Validate | 1.53M/s | 5.4x faster | 6.2x faster | — | | Format E.164 | 32.4M/s | 4.3x faster | 1.5x faster | 1.9x faster | | Format Intl | 2.30M/s | 7.3x faster | 6.1x faster | 6.2x faster | | Full pipeline | 1.51M/s | 4.8x faster | 11.2x faster | — | | Batch (10 nums) | 160K/s | 7.4x faster | 5.7x faster | 38x faster |

Benchmarks on Apple M1 Ultra, Node.js v24. Sync API with pre-loaded metadata. Run pnpm benchmark to reproduce.

Why so fast?

Hand-optimized data structures from official Google data:

  • Pre-compiled RegExp literals — All patterns (validation, formatting, leading digits) are compiled at build time, not runtime. Zero new RegExp() calls during validation.
  • Bitmap-based length validation — Possible lengths stored as bit flags for O(1) membership checks instead of array iteration.
  • Combined leading digit patterns — Multiple patterns merged into single RegExp with | alternation, eliminating array traversal.
  • Zero-overhead sync API — When metadata is pre-loaded, no async overhead at all.
  • Lean metadata — Only LANDLINE, MOBILE, VOIP patterns included. No toll-free, premium, or special service bloat.

All metadata is automatically generated from Google's official PhoneNumberMetadata.xml — the same source used by libphonenumber — ensuring correctness while maximizing performance.

Development

# Install dependencies
pnpm install

# Run tests
pnpm test

# Run type checking
pnpm typecheck

# Run linting
pnpm lint

# Build
pnpm build

# Run benchmarks
pnpm benchmark

License

Apache-2.0

Based on concepts from Google's libphonenumber.

Contributing

See CONTRIBUTING.md for guidelines.