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

qr-local-dev

v0.5.3

Published

Print a QR code for your local dev server in the terminal

Readme

qr-local-dev

Display a QR code in your terminal that points to your machine's local network URL, so you can open your dev server on a phone or another computer instantly.

Install

npm i -D qr-local-dev

Or use it globally:

npm i -g qr-local-dev

CLI

qr-local -p 3000

Options:

  • -p, --port <number>: Port to include in the URL (e.g., 3000)
  • --ports <list>: Comma list of ports to try (e.g., 3000,5173,8080)
  • --http/--https or --protocol <p>: http | https | auto
  • --path <path>: Optional path to append (e.g., /app)
  • -H, --host <ip>: Override detected host/IP
  • -s, --small: Use smaller terminal QR variant
  • -d, --detect: Try common ports and pick a running dev server
  • -c, --copy: Copy the resolved URL to your clipboard
  • --mdns: Broadcast via mDNS/Bonjour (if available)
  • --mdns-name <n>: Custom mDNS service name
  • --force-qr: Print QR even if not a TTY
  • -w, --wait: Wait for the server to become available
  • --wait-timeout <ms>: Max wait time in ms (default 15000)
  • --wait-interval <ms>: Probe interval in ms (default 500)
  • --square: Render square-style QR (uses qrcode-terminal)

API

const { printLocalhostQR } = require("qr-local-dev");

await printLocalhostQR({ port: 3000 });

// Auto-detect server and protocol (useful across frameworks)
await printLocalhostQR({
  protocol: "auto",
  detect: true,
  small: true,
  square: true,
  copy: true,
  mdns: true,
  wait: true,
  waitTimeout: 15000,
  waitInterval: 500,
});

TypeScript users: this package ships .d.ts types. Import as:

import { printLocalhostQR } from "qr-local-dev";

Express example

const express = require("express");
const { printLocalhostQR } = require("qr-local-dev");

const app = express();
const port = process.env.PORT || 3000;

app.get("/", (_req, res) => {
  res.send("Hello from Express");
});

app.listen(port, async () => {
  await printLocalhostQR({ port });
});

Next.js: auto-print QR on dev start (no extra scripts)

Add an instrumentation file so the QR shows right after npm run dev:

  1. Create instrumentation.js or instrumentation.ts at your project root:
// instrumentation.(js|ts) (Next.js App Router)
export async function register() {
  // Only run in Node.js runtime (skip Edge) and only in dev
  if (process.env.NEXT_RUNTIME !== "nodejs") return;
  if (process.env.NODE_ENV === "production") return;

  // Prevent duplicate prints during Fast Refresh
  const shownKey = "__qr_local_dev_shown__";
  if ((globalThis as any)[shownKey]) return;
  (globalThis as any)[shownKey] = true;

  const { printLocalhostQR } = await import("qr-local-dev");

  const envBool = (v?: string) => v === "1" || v === "true";
  const portsEnv = process.env.QR_LOCAL_PORTS;
  const ports = portsEnv
    ? portsEnv
        .split(",")
        .map((p) => Number(p.trim()))
        .filter(Boolean)
    : undefined;

  const delay = Number(process.env.QR_LOCAL_DELAY ?? 300);

  setTimeout(() => {
    printLocalhostQR({
      protocol: process.env.QR_LOCAL_PROTOCOL || "auto",
      detect: envBool(process.env.QR_LOCAL_DETECT ?? "1"),
      wait: envBool(process.env.QR_LOCAL_WAIT ?? "1"),
      waitTimeout: Number(process.env.QR_LOCAL_WAIT_TIMEOUT ?? 15000),
      waitInterval: Number(process.env.QR_LOCAL_WAIT_INTERVAL ?? 500),
      small: envBool(process.env.QR_LOCAL_SMALL ?? "1"),
      square: envBool(process.env.QR_LOCAL_SQUARE ?? "0"),
      copy: envBool(process.env.QR_LOCAL_COPY ?? "0"),
      mdns: envBool(process.env.QR_LOCAL_MDNS ?? "0"),
      mdnsName: process.env.QR_LOCAL_MDNS_NAME,
      forceQr: envBool(process.env.QR_LOCAL_FORCE_QR ?? "0"),
      host: process.env.QR_LOCAL_HOST,
      path: process.env.QR_LOCAL_PATH || "",
      port: process.env.PORT ? Number(process.env.PORT) : undefined,
      ports,
    }).catch(() => {});
  }, delay);
}
  1. Pin your dev port so the QR matches:
{
  "scripts": {
    "dev": "next dev -p 3000"
  }
}
  1. Run your app as usual:
npm run dev

Optional HTTPS:

next dev -p 3000 --experimental-https

If you use HTTPS, set protocol: "https" in printLocalhostQR.

Troubleshooting:

  • Requires App Router (instrumentation file convention). For Pages Router-only apps, use the CLI approach.
  • Ensure the file name is exactly instrumentation.js or instrumentation.ts in your project root (or app/).
  • If the port can change, use --wait/detect or pin the port with -p.

Framework tips

  • Vite (React/Vue/Svelte/Solid): default ports 5173/4173; use --protocol auto --detect --ports 5173,4173
  • Next.js: default 3000; use instrumentation above or concurrently with next dev -p 3000
  • Nuxt: default 3000; prefer --protocol auto --detect --ports 3000,4000
  • Astro: default 4321; use --protocol auto --detect --ports 4321
  • SvelteKit: default 5173; use --protocol auto --detect --ports 5173
  • Angular: default 4200; use --protocol auto --detect --ports 4200
  • Vue CLI: default 8080; use --protocol auto --detect --ports 8080

General advice:

  • Pin your dev port to keep the QR stable (avoid auto-increment ports).
  • If your dev server switches to HTTPS, --protocol auto will probe and pick it.
  • Add -c/--copy so you can paste the URL quickly on your device.

Framework recipes (copy/paste)

Install helpers once:

npm i -D concurrently wait-on

Add one of these to your app's package.json scripts.

  1. Next.js (Pages Router only):
{
  "scripts": {
    "dev": "concurrently -k -s first \"next dev -p 3000\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --wait\""
  }
}
  1. Vite (React/Vue/Svelte/Solid):
{
  "scripts": {
    "dev": "concurrently -k -s first \"vite\" \"wait-on http://localhost:5173 && qr-local --protocol auto --detect --ports 5173,4173 --wait\""
  }
}
  1. Nuxt:
{
  "scripts": {
    "dev": "concurrently -k -s first \"nuxi dev -p 3000\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --wait\""
  }
}
  1. Astro:
{
  "scripts": {
    "dev": "concurrently -k -s first \"astro dev\" \"wait-on http://localhost:4321 && qr-local --protocol auto --detect --ports 4321 --wait\""
  }
}
  1. SvelteKit:
{
  "scripts": {
    "dev": "concurrently -k -s first \"vite\" \"wait-on http://localhost:5173 && qr-local --protocol auto --detect --ports 5173 --wait\""
  }
}
  1. Angular:
{
  "scripts": {
    "dev": "concurrently -k -s first \"ng serve --host 0.0.0.0 --port 4200\" \"wait-on http://localhost:4200 && qr-local --protocol auto --detect --ports 4200 --wait\""
  }
}
  1. Vue CLI:
{
  "scripts": {
    "dev": "concurrently -k -s first \"vue-cli-service serve --host 0.0.0.0 --port 8080\" \"wait-on http://localhost:8080 && qr-local --protocol auto --detect --ports 8080 --wait\""
  }
}
  1. Remix:
{
  "scripts": {
    "dev": "concurrently -k -s first \"remix dev\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --ports 3000 --wait\""
  }
}

Notes:

  • Use --square for a square-looking QR: append --square to the QR command.
  • Add --copy to copy URL to clipboard automatically.
  • For HTTPS, prefer --protocol auto (it will probe) or pass --https.

WSL (Windows Subsystem for Linux)

  • Your LAN IP might differ between Windows and WSL. This tool uses os.networkInterfaces() inside the current runtime.
  • If mobile cannot reach the URL, try overriding host with the Windows LAN IP: qr-local -H 192.168.x.y -p 3000.
  • If the port is forwarded or bound to 127.0.0.1 only, ensure your dev server binds to 0.0.0.0.

Docker/containers

  • On Linux, --network host allows containers to use the host network (QR will point to the host IP).
  • Otherwise, expose the port and run the QR command on the host, not inside the container.

TTY/CI

  • Some environments pipe output; the QR may be hidden. Use --force-qr to print anyway or rely on the URL line.
  • You can disable QR (URL only) by omitting --force-qr in non-TTY contexts.