# Generate a QR code in Node.js

> In Node, the qrcode npm package covers everything offline: QRCode.toFile for files, toDataURL for embedding, toString for SVG, and toFileStream to pipe PNG straight into an HTTP response. If you would rather not own an imaging dependency, fetch the keyless API and relay the bytes.

Source: https://useqr.app/docs/developers/generate-a-qr-code-in-node · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## The qrcode package

`npm install qrcode` gives you the ecosystem's standard server-side generator. Four output
methods cover nearly every case:

```js
import QRCode from "qrcode";

await QRCode.toFile("qr.png", "https://example.com", { margin: 4, width: 1024 });
const dataUrl = await QRCode.toDataURL("https://example.com");
const svg = await QRCode.toString("https://example.com", { type: "svg", margin: 4 });
const terminal = await QRCode.toString("hello", { type: "terminal" });
```

That last one prints a scannable code into stdout — handy for CLI tools that want to hand a
URL to a phone. `margin: 4` is the 4-module [quiet zone](/glossary/quiet-zone); do not
trim it.

## Streaming into an HTTP response

`toFileStream` accepts any writable stream, and an HTTP response is one. No temp files, no
buffering the whole image:

```js
import http from "node:http";
import QRCode from "qrcode";

http.createServer((req, res) => {
  const data = new URL(req.url, "http://x").searchParams.get("data") ?? "hello";
  res.writeHead(200, {
    "Content-Type": "image/png",
    "Cache-Control": "public, max-age=31536000, immutable",
  });
  QRCode.toFileStream(res, data, { margin: 4, width: 512 });
}).listen(3000);
```

The `immutable` cache header is correct here because the same input always produces the
same code — let browsers and CDNs keep it. The same idea in a framework context is on the
[Next.js page](/docs/developers/generate-a-qr-code-in-nextjs), and constraints for
Lambda-style runtimes are in
[QR codes in serverless functions](/docs/developers/qr-codes-in-serverless-functions).

## Batch generation

For a run of codes — one per order, per ticket, per asset — a plain loop is fine into the
thousands, because `qrcode` is pure JavaScript with no native imaging binary:

```js
import QRCode from "qrcode";

for (const { slug, url } of rows) {
  await QRCode.toFile(`codes/${slug}.svg`, url, { type: "svg", margin: 4 });
}
```

Write SVG for anything destined for [print](/docs/print/qr-code-size-for-print) — it is
smaller than PNG at print resolution and never pixelates. Scaling patterns, concurrency and
file-naming discipline are covered in
[bulk QR generation at scale](/docs/developers/bulk-qr-generation-at-scale).

## When to proxy the API instead

The [keyless API](/docs/developers/free-qr-code-api-no-key) earns its place when you want
styling (module shapes, eye styles, colours) without writing renderer code, typed payload
builders (`/api/v1/wifi`, `/api/v1/upi`) with server-side validation, or simply zero
dependencies:

```js
const res = await fetch(
  `https://useqr.app/api/v1/qr?data=${encodeURIComponent(url)}&size=1024&ec=Q`
);
await fs.promises.writeFile("qr.png", Buffer.from(await res.arrayBuffer()));
```

Generate locally when payloads are sensitive (credentials never belong in someone else's
request logs) or when the network is off the table.

## Close the loop: decode what you made

Rendering a matrix does not prove the output scans, especially once styling or logos are
involved. One extra call closes the loop:

```js
const report = await fetch(
  `https://useqr.app/api/v1/verify?data=${encodeURIComponent(url)}&color=6366f1`
).then((r) => r.json());
if (!report.scannable) throw new Error(report.issues.join("; "));
```

Reasoning and alternatives (zxing-wasm locally) in
[why verify that your QR code decodes](/docs/developers/why-verify-that-your-qr-code-decodes).

## FAQ

### What is the standard QR library for Node.js?
The qrcode npm package. It is pure JavaScript, needs no native imaging dependency, and outputs files, data URLs, SVG strings and streams.

### How do I return a QR code from an HTTP endpoint?
Set Content-Type to image/png and pass the response object to QRCode.toFileStream. Add an immutable cache header, since identical input always yields identical bytes.

### Should I generate PNG or SVG on the server?
SVG for print and for anything that might be resized; PNG for fixed-size screen display and email clients. The qrcode package produces both.

### How do I know the generated code actually scans?
Decode it back. Call GET /api/v1/verify with the same data and styling, or run zxing-wasm locally, and fail the job if the report says it is not scannable.

## Try it

- https://useqr.app/url
- https://useqr.app/json
- https://useqr.app/validate
