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

@abdullahharunozturk/localtld

v0.1.2

Published

Give your local projects real domains on dynamic ports — access panel.aaron.localtld instead of chasing ports.

Downloads

104

Readme

localtld

Give your local projects real domains on dynamic ports. Stop chasing ports — reach your app at panel.aaron.localtld.

// package.json
{ "localtld": "panel.aaron" }
localtld run -- pnpm dev
#   → http://panel.aaron.localtld   (dynamic port — you never need to know it)

Whatever port your dev server grabs (3000, 51234, doesn't matter), you always reach it at the same clean domain. Run hundreds of projects at once: no port collisions, nothing to track.

Zero-config, even if you've never heard of localtld

Wire it once in a project and it just works on any machine that has localtld set up — the developer doesn't need to know localtld exists:

// package.json
{
  "localtld": "panel.aaron",
  "scripts": {
    "dev": "if command -v localtld >/dev/null 2>&1; then localtld run -- next dev; else next dev; fi"
  },
  "optionalDependencies": {
    "@abdullahharunozturk/localtld": "^0.1.0"
  }
}

Now the normal workflow does everything:

pnpm install     # on macOS the localtld binary lands in node_modules/.bin
pnpm dev

Why optionalDependencies + the guard, not a plain devDependencies entry:

  • localtld is macOS-only ("os": ["darwin"]). As an optional dependency, Linux/Windows/CI skip it silently — a regular dependencies/devDependencies entry would fail the whole install with EBADPLATFORM.
  • The command -v guard lets the dev script survive on any machine where the binary isn't present (non-macOS, or one that skipped it).

Result — zero action required from your teammates, and nobody needs to know localtld exists:

| Machine | pnpm install | pnpm dev | |---------|----------------|------------| | macOS, set up | installs localtld | panel.aaron.localtld | | macOS, not set up | installs localtld | offers localtld setup, else localhost | | Linux / Windows / CI | skips it (no error) | plain next dev on localhost |

Without adding a dependency

Don't want localtld in your devDependencies (or it isn't installed on every machine)? Guard the script so it degrades to a plain run when the binary is absent:

// package.json
{
  "localtld": "panel.aaron",
  "scripts": {
    "dev": "if command -v localtld >/dev/null 2>&1; then localtld run -- next dev; else next dev; fi"
  }
}
  • Machine has the localtld binary → pretty domain.
  • Machine doesn't → plain next dev (localhost:PORT), no error, zero dependency.

command -v is POSIX sh (macOS/Linux). Use this when you want the repo to carry zero localtld dependency — no devDependencies entry, no assumption that any teammate has it installed. (Prefer the pinned devDependencies approach above if you'd rather everyone get the same domain automatically.)

How it works

localtld doesn't reinvent anything; it orchestrates two standard tools:

browser → panel.aaron.localtld
   │  dnsmasq:  *.localtld → 127.0.0.1        (+ macOS /etc/resolver)
   ▼
127.0.0.1:80 → Caddy  (Host header → the right port)
   ▼
127.0.0.1:51234 ← your dev server (localtld assigned it via PORT env)
  • TLD is fixed (.localtld) — identical on every machine, so shared configs, docs and bug reports always match.
  • Label is a project-level setting (package.json) — one line, no TLD in it, so the repo stays portable.
  • Opt-in & graceful: without a system setup, projects just run on localhost:PORT.

Environment variables (.env)

localtld changes the host your dev server is reachable at — it doesn't touch your app config. When services talk to each other by URL (a frontend calling an API, CORS origins, …), those URLs differ between the two worlds:

  • localtld ONhttp://core.aaron.localtld (port 80, via Caddy)
  • localtld OFFhttp://localhost:3001

.env files are static and ${VAR} expansion isn't portable across tools, so the simplest pattern is to ship both and let each machine pick. Default to localhost in code so the project runs with zero config:

# .env.example

# localtld OFF (default):
CORE_API_URL=http://localhost:3001/api
# localtld ON:
# CORE_API_URL=http://core.aaron.localtld/api
// default to localhost → works even without localtld
const base = process.env.CORE_API_URL ?? 'http://localhost:3001/api';

A teammate copies .env.example.env; if they use localtld, they swap the commented line. Keep the URL in .env (or the .env.example comment) rather than hardcoded in source — not every machine runs localtld, and the localhost fallback needs to keep working.

Install

# Homebrew (primary)
brew install abdullahharunozturk/localtld/localtld

# or npm (CLI is still `localtld`)
npm install -g @abdullahharunozturk/localtld

# or curl (coming soon — needs localtld.sh to be live)
# curl -fsSL https://localtld.sh | bash

localtld setup               # configure dnsmasq + Caddy (asks for sudo)

Requires macOS + Homebrew. Brew pulls in caddy, dnsmasq, and jq automatically; via npm/curl, setup installs them if missing.

Commands

| Command | What it does | |---------|--------------| | localtld setup | First-time setup: configure dnsmasq/Caddy | | localtld run -- <cmd> | Run a project under its domain (falls back if not set up) | | localtld list | Show active projects and their domains | | localtld doctor | Check the health of your setup | | localtld uninstall | Revert DNS/route changes |

Why .localtld is fixed

Every project gets <label>.localtld — the suffix is deliberately not configurable. One standard suffix means a shared package.json entry, a doc snippet or a bug report works identically on every machine, and .localtld is not a real TLD so it can never collide with a live website.

Want a different suffix? Fork and edit the single TLD= line at the top of bin/localtld. A built-in guard refuses forks that set a real TLD (.com, .dev, …), since every site under it would resolve to 127.0.0.1 on the user's machine.

Upgrading from an older version with a custom TLD? It is no longer read — the tool warns once and uses .localtld; run localtld setup again to re-wire DNS.

License

MIT © Abdullah Harun Öztürk