qr-local-dev
v0.5.3
Published
Print a QR code for your local dev server in the terminal
Maintainers
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-devOr use it globally:
npm i -g qr-local-devCLI
qr-local -p 3000Options:
-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/--httpsor--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:
- Create
instrumentation.jsorinstrumentation.tsat 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);
}- Pin your dev port so the QR matches:
{
"scripts": {
"dev": "next dev -p 3000"
}
}- Run your app as usual:
npm run devOptional HTTPS:
next dev -p 3000 --experimental-httpsIf 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.jsorinstrumentation.tsin your project root (orapp/). - If the port can change, use
--wait/detector 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
concurrentlywithnext 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 autowill probe and pick it. - Add
-c/--copyso you can paste the URL quickly on your device.
Framework recipes (copy/paste)
Install helpers once:
npm i -D concurrently wait-onAdd one of these to your app's package.json scripts.
- 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\""
}
}- 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\""
}
}- Nuxt:
{
"scripts": {
"dev": "concurrently -k -s first \"nuxi dev -p 3000\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --wait\""
}
}- Astro:
{
"scripts": {
"dev": "concurrently -k -s first \"astro dev\" \"wait-on http://localhost:4321 && qr-local --protocol auto --detect --ports 4321 --wait\""
}
}- SvelteKit:
{
"scripts": {
"dev": "concurrently -k -s first \"vite\" \"wait-on http://localhost:5173 && qr-local --protocol auto --detect --ports 5173 --wait\""
}
}- 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\""
}
}- 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\""
}
}- Remix:
{
"scripts": {
"dev": "concurrently -k -s first \"remix dev\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --ports 3000 --wait\""
}
}Notes:
- Use
--squarefor a square-looking QR: append--squareto the QR command. - Add
--copyto 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 hostallows 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-qrto print anyway or rely on the URL line. - You can disable QR (URL only) by omitting
--force-qrin non-TTY contexts.
