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

its-not-dns

v0.1.0

Published

"It's not DNS. There's no way it's DNS. It was DNS." — the haiku, as a diagnostic. npx its-not-dns yoursite.com walks the blame chain (hosts file → resolvers → records → TCP → TLS → HTTP) and prints the verdict. Compares your system resolver against 1.1.1

Readme

its-not-dns

It's not DNS.There's no way it's DNS.It was DNS.

The haiku, as a diagnostic.

npm version CI types license

npx its-not-dns yoursite.com

"The site is down" hits the channel. Someone says it loads fine for them. Someone blames the CDN. Someone restarts the pod. Forty minutes later it's a stale DNS record, like it always was.

its-not-dns walks the whole blame chain in order — hosts file → system resolver vs 1.1.1.1 vs 8.8.8.8 → records & CNAME chain → TCP to every resolved IP → TLS certificate → HTTP redirects — and ends with a verdict, not a data dump:

  api.example.com:443 (https)

  “It's not DNS.”
    ✓ no /etc/hosts override
    ✓ A @system: 104.20.23.154, 172.66.147.243 (3 ms)
    ✓ A @1.1.1.1: 104.20.23.154, 172.66.147.243 (5 ms)
    ✓ A @8.8.8.8: 104.20.23.154, 172.66.147.243 (36 ms)
    ✓ getaddrinfo: 104.20.23.154, 172.66.147.243 (44 ms)

  “There's no way it's DNS.”
    ✓ tcp 104.20.23.154:443 (35 ms)
    ✓ tcp 172.66.147.243:443 (39 ms)
    ✗ tls: CERT_EXPIRED

  “It wasn't DNS. It was the certificate.”

  The TLS certificate expired 41 day(s) ago (Apr 12 23:59:59 2026 GMT).
  fix: Renew the cert / check the auto-renewal job that silently died.

And when it is DNS — and it's always DNS — you get to paste this in the channel:

  “It was DNS.”

What it actually catches

| Layer | The classics it names | | ----- | --------------------- | | hosts file | The /etc/hosts pin from an incident six months ago, still shadowing prod for every app on your laptop | | Resolvers | NXDOMAIN; split-horizon (corp DNS says one thing, 1.1.1.1 another); mid-propagation changes; system cache vs raw DNS (getaddrinfo disagreeing with the wire) | | Records | Domains with no A/AAAA left; CNAME chains; v6-only/v4-only mismatches ("curl works, the app doesn't") | | TCP | All resolved IPs dead (that's an outage, not DNS) — or only some dead, the "works every other refresh" special | | TLS | Expired certs (with day count), not-yet-valid certs (clock skew), hostname mismatches (SANs listed), self-signed chains | | HTTP | Redirect loops (CDN ↔ origin https confusion), 5xx, slow first byte |

One culprit wins — by the priority order of what actually breaks in practice — and every verdict comes with a one-line fix.

Install

npx its-not-dns yoursite.com     # no install
npm i -g its-not-dns             # keep it for the next incident

Node ≥ 18. Zero runtime deps beyond the CLI niceties (cac, picocolors). No API key, no service, no telemetry — the only traffic is to your target and the public resolvers being compared.

Usage

its-not-dns api.example.com                  # full chain, https:443
its-not-dns http://10.0.0.5:3000/health      # URLs, ports, paths
its-not-dns shop.example.com --resolver 10.0.0.2   # also ask your corp DNS (split-horizon hunting)
its-not-dns api.example.com --no-http        # stop after DNS/TCP/TLS
its-not-dns api.example.com --md incident.md # markdown for the postmortem
its-not-dns api.example.com --json | jq .verdict
it-was-dns api.example.com                   # same tool — for when you already know

Exit codes: 0 = everything checks out · 1 = found a culprit · 2 = usage error. So you can even use it as a smoke test:

- run: npx its-not-dns api.example.com || echo "::warning::$(npx its-not-dns api.example.com --md -)"

Real scenarios

1. "It's down for customers but fine for us." Run it where it's broken (or have the customer run it — it's an npx one-liner). Resolver disagreement and hosts-file pins show up instantly, with the line number.

2. The 3 a.m. cert. ✗ tls: CERT_EXPIRED — expired 0 day(s) ago is a different conversation than "the site is down". The verdict names the layer before anyone restarts anything.

3. Split-horizon hunting. --resolver 10.0.0.2 adds your corp/VPN DNS to the comparison table. When it answers differently than 1.1.1.1, you've found your "works off VPN" bug.

Library API

The verdict engine is pure — feed it findings from anywhere (tests do):

import { analyze, parseTarget, findHostsOverrides } from "its-not-dns";

const diagnosis = analyze(findings);   // findings: what the probes gathered
diagnosis.verdict;  // { wasDns: true, culprit: "resolver-disagreement", line: "It was DNS.", fix: "…" }
diagnosis.lines;    // the ✓/✗ lines under each verse

Roadmap

  • --watch — re-run until the verdict changes (TTL countdowns during failover).
  • DNSSEC validation check; --doh (DNS-over-HTTPS) comparison.
  • MX/TXT modes for "my email is down" (its-not-dns --mx example.com).
  • A --compare mode: run on two machines, diff the verdicts (womm-style).

💖 Sponsor

Free, MIT, built in spare time. If this ended a blame-storm before it started:

License

MIT © its-not-dns contributors