tld.js

Parses hostnames and URLs to reliably extract domains, subdomains, and public suffixes using Mozilla's public suffix list.

Library
npm
v2.3.2
477stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
43/100Fair
Development Activity0
Maintenance20
Community72
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture78
Code Quality75
Innovation72
Learning Curve55

tld.js is a small, dependency-light JavaScript library for answering questions about hostnames and URLs that plain string-splitting gets wrong: what is the registrable domain of mail.google.com? What is the subdomain of a.b.ide.kyoto.jp? Is big.data’s TLD actually a well-known one? Instead of guessing from the last dot, it looks up each hostname against Mozilla’s public suffix list, which correctly treats multi-part suffixes like co.uk or s3.amazonaws.com as a single unit.

The library ships as a factory function that builds an instance around a Trie of suffix rules, and exposes both a single parse() call that returns every derived property at once and single-purpose shorthands (getDomain, getSubdomain, getPublicSuffix, tldExists, isValidHostname) for callers who only need one value. It runs equally well in Node.js and in the browser (via browserify/webpack), and supports custom valid-host lists for cases like localhost that aren’t real TLDs but should still resolve to a domain.

What You Get

  • A single parse(url) call that returns hostname, isValid, isIp, tldExists, publicSuffix, domain, and subdomain in one pass
  • Single-purpose shorthand functions (getDomain, getSubdomain, getPublicSuffix, tldExists, isValidHostname) for callers who only need one value
  • A bundled, Trie-indexed copy of Mozilla’s public suffix list with an opt-in --tldjs-update-rules install flag to refresh it
  • A fromUserSettings() factory for creating a customized instance with additional valid hosts (e.g. localhost) or a custom hostname-extraction function
  • Browser-ready builds (tld.js, tld.min.js) alongside the CommonJS build, so the same API works client- and server-side

Common Use Cases

  • Grouping or comparing URLs by their registrable domain (e.g. treating mail.google.com and docs.google.com as the same site)
  • Validating and normalizing user-submitted hostnames before storing or looking them up
  • Cookie-scoping and same-site logic that needs the correct eTLD+1 rather than a naive last-two-labels guess
  • Filtering or classifying links by public suffix in crawlers, ad-blockers, or analytics pipelines
  • Detecting whether a given string is an IP address versus a real hostname before applying domain logic

Under The Hood

Architecture tld.js is organized as a single factory() function in index.js that assembles a set of independent, single-responsibility modules under lib/clean-host.js (hostname extraction from arbitrary URL forms), is-valid.js (RFC 1035 validation), is-ip.js (IP detection), suffix-trie.js (a Trie built from the bundled rules.json public suffix list), public-suffix.js, domain.js, and subdomain.js. The core parse() function threads a hostname through these stages with numeric step flags (TLD_EXISTS, PUBLIC_SUFFIX, DOMAIN, SUB_DOMAIN, ALL) that let single-purpose shorthands like getDomain() stop early instead of computing the full result — a deliberate laziness optimization given the library’s own published benchmarks. fromUserSettings() re-invokes the same factory with overridden rules, validHosts, or extractHostname, so customization happens by producing a new instance rather than mutating global state.

Tech Stack The published library is plain CommonJS JavaScript (ES5-style var declarations, no TypeScript, no build step for the main entry point) with a single runtime dependency, punycode@^2.3.1. Browser bundles (tld.js, tld.min.js) are produced from the same source via browserify and uglify-js, and package.json’s exports map points import at the browserified build and require at index.js. Tooling includes ESLint 9’s flat config (eslint.config.mjs) with the js/recommended ruleset, mocha + nyc for tests and coverage, benchmark.js for the documented perf numbers, and a GitHub Actions workflow (.github/workflows/main.yml) that installs, tests, reports coverage via Coveralls, and publishes to npm on tagged pushes.

Code Quality test/tld.js and test/publicsuffix.js provide extensive mocha/expect.js assertions covering edge cases (malformed hostnames, IP literals, trailing dots, case sensitivity, maximum-length hostnames), and nyc is configured with check-coverage: true plus HTML/lcov/text reporting, with posttest chaining into eslint. Functions carry JSDoc @param/@return/@typedef annotations throughout lib/ and index.js even though the project isn’t written in TypeScript, which gives editor tooling reasonable type hints. One gap: the README links to a CONTRIBUTING.md that isn’t actually present in the repository.

API Design The public surface is deliberately small and consistently named — parse, tldExists, getDomain, getSubdomain, getPublicSuffix, isValidHostname, plus fromUserSettings for customization — and every method is documented in the README with runnable input/output examples. The deprecated isValid alias uses Node’s util.deprecate to warn callers toward isValidHostname instead of silently breaking them. Getting started requires nothing more than require('tldjs') and calling a function; the tradeoff is that no TypeScript type declarations are published with the package, so TypeScript consumers must rely on community @types or write their own.

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

Search