psl

A lightweight JavaScript domain parser that resolves any hostname against the Public Suffix List.

Library
npm
v1.15.0
439 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
38 /100 Needs Attention
Development Activity 0
Maintenance 20
Community 52
Maturity 60
Momentum 20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
64 /100 Good
Architecture 75
Code Quality 82
Innovation 45
Learning Curve 55

psl is a JavaScript implementation of Mozilla’s Public Suffix List, letting you split any hostname into its top-level domain, registrable domain, and subdomain parts. Rather than relying on naive heuristics like counting dots, it looks up each label against the community-maintained suffix rules, correctly handling multi-part suffixes like co.uk, wildcard rules like *.kobe.jp, and exceptions, plus punycode-encoded internationalized domain names.

Published as psl on npm with tens of millions of weekly downloads, it ships as ESM, CommonJS, and a UMD bundle for direct browser use via CDN, and is a foundational dependency inside tools like tough-cookie/request for correct cookie-domain scoping.

What You Get

  • psl.parse(domain) returns the full breakdown into tld/sld/domain/subdomain, plus a typed error object for malformed input instead of throwing
  • psl.get(domain) is a quick-lookup helper that returns just the registrable domain, or null if the input isn’t valid
  • psl.isValid(domain) returns a boolean for whether a domain has a recognized public suffix
  • Prebuilt ESM, CJS, and UMD bundles plus bundled TypeScript type definitions, so it drops into Node, a bundler, or a plain <script> tag from a CDN

Common Use Cases

  • Scoping cookies to the correct registrable domain instead of an entire public suffix, preventing cross-site cookie leakage
  • Splitting a multi-tenant SaaS hostname into its subdomain and base domain for tenant routing
  • Normalizing domains (e.g. www.acme.com and acme.com) to the same registrable domain for analytics or deduplication
  • Validating user-submitted domain fields before storing or looking them up

Under The Hood

Architecture

The entire library is effectively one data structure plus three pure functions built on top of it: data/rules.js (regenerated from publicsuffix.org via scripts/update-rules.js) is folded at load time in index.js into a Map keyed by punycode-encoded suffix, so findRule() can resolve a domain’s matching rule by walking candidate suffixes from most-specific to least. parse(), get(), and isValid() are thin layers on top of that single lookup — there’s no class hierarchy, dependency injection, or I/O beyond the bundled rules data. Because parse, findRule, and validate all share the same rule-object shape (wildcard/exception/punySuffix), changing that representation would require touching all three together.

Tech Stack

Plain JavaScript authored as an ES module, with a single runtime dependency (punycode v2) for IDN handling. Vite builds the ESM/CJS/UMD bundles, and TypeScript (via typescript-eslint) is used only to author and check the bundled .d.ts definitions, not to compile the runtime code. Tests run on Mocha with Node’s built-in assert, alongside a separate BrowserStack/Playwright suite for real-browser coverage. There is no framework, ORM, or database — this is a pure parsing utility.

Code Quality

Test coverage is thorough for a library this size: dedicated spec files for parse, get, and isValid run against Mozilla’s own canonical PSL test fixtures as well as hand-written cases for wildcards, exceptions, and punycode-encoded IDNs. Invalid input is modeled as typed, explicit error codes rather than swallowed or thrown for expected cases, while true programmer errors (a non-string input) raise a TypeError. ESLint’s flat config with typescript-eslint recommended rules, plus a GitHub Actions matrix spanning legacy and current Node versions and browsers, run on every push.

What Makes It Unique

psl doesn’t invent a new algorithm — domain-suffix matching against the canonical Public Suffix List is a well-understood problem — but it’s one of the most widely adopted JavaScript implementations of it, embedded inside libraries like tough-cookie/request for correct cookie scoping, and its compact rules-array-plus-Map lookup is a pragmatic, extensively tested reference implementation rather than a novel technique.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers