Build a QR code service

A small Node.js service that turns any text or URL into a QR code — served as a live PNG or as a data-URL for your own pages, with the full code and run steps.

QR codes are the easiest way to hand a link to a phone. This guide builds a tiny web service that turns any text or URL into a QR code — you can drop its image URL straight into an <img> tag, print it, or share it. It runs on the Node.js application using the qrcode package, and it's small enough to read in one sitting.

At a glance
You need A server running the Node.js application
Build with Express + the qrcode package
Plan Any — free runs while your session timer has time, premium runs 24/7
Time About fifteen minutes

If Node is new to you, Node.js on Falix covers the index.js entry file, automatic npm install, and the SERVER_PORT rule this uses.

What you're building

Endpoint Returns Use it for
/qr.png?text=... A PNG image streamed to the browser <img src="/qr.png?text=...">, printing, sharing a URL
/qr.json?text=... JSON with a data: URL Embedding the code inline without a second request

Two shapes of the same thing: a real image file, or a base64 data: URL you can paste anywhere.

Step 1 — Create the project files

In the File Manager, create package.json:

{
  "name": "qr-generator",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "express": "^4.19.2",
    "qrcode": "^1.5.4"
  }
}

Then index.js — the whole service:

const express = require('express');
const QRCode = require('qrcode');
const path = require('node:path');

const app = express();
app.use(express.static(path.join(__dirname, 'public')));

// /qr.png?text=...  -> a PNG image streamed straight to the browser
app.get('/qr.png', async (req, res) => {
  const text = (req.query.text || '').toString();
  if (!text) return res.status(400).json({ error: 'Pass ?text=' });
  try {
    res.type('image/png');
    await QRCode.toFileStream(res, text, { width: 300, margin: 2 });
  } catch (err) {
    console.error('qr failed:', err.message);
    res.status(422).json({ error: 'Could not encode that text.' });
  }
});

// /qr.json?text=...  -> a data: URL you can drop into an <img src="">
app.get('/qr.json', async (req, res) => {
  const text = (req.query.text || '').toString();
  if (!text) return res.status(400).json({ error: 'Pass ?text=' });
  try {
    const dataUrl = await QRCode.toDataURL(text, { width: 300, margin: 2 });
    res.json({ text, dataUrl });
  } catch (err) {
    res.status(422).json({ error: 'Could not encode that text.' });
  }
});

const PORT = process.env.SERVER_PORT || 8080;
app.listen(PORT, '0.0.0.0', () => console.log(`Listening on port ${PORT}`));

Optionally add a test page at public/index.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>QR generator</title></head>
<body>
  <h1>QR code</h1>
  <img src="/qr.png?text=https://falixnodes.net" alt="QR code" width="300">
</body>
</html>

Step 2 — Start it

Press Start. Falix runs npm install (because package.json exists), then your code prints:

Listening on port 25565

That's your online signal.

Step 3 — Try it

Open your server's address (from the Network page) with a text query:

http://YOUR_ADDRESS:PORT/qr.png?text=https://falixnodes.net

You get a scannable PNG. Point your phone camera at it and it opens the link. The JSON version returns something like:

{ "text": "hello", "dataUrl": "data:image/png;base64,iVBORw0KGgo..." }

That dataUrl goes straight into an image tag — <img src="data:image/png;base64,..."> — so a page can show a QR code without a second network request.

💡 Tip: Because /qr.png is just a URL, you can embed live QR codes anywhere: <img src="https://YOUR_ADDRESS:PORT/qr.png?text=YOUR_LINK">. Change the text and the code changes.

How it works

The two endpoints use two qrcode functions:

  • QRCode.toFileStream(res, text, ...) pipes the PNG bytes directly into the response stream. You set res.type('image/png') first so the browser treats it as an image, then let qrcode write to it. No temp files.
  • QRCode.toDataURL(text, ...) returns a base64 data: string instead — handy when you'd rather inline the image than serve it.

The { width: 300, margin: 2 } options set the pixel size and the quiet-zone border. Everything beyond that — error-correction levels, colors, SVG output — is standard qrcode; its official documentation on the node-qrcode project page covers the rest.

🎯 Good to know: QR codes have a capacity limit — a URL or a few hundred characters is fine, but very long text produces a dense, hard-to-scan code (or fails to encode). Keep the payload short; that's what URL shorteners are for. You could even pair this with the URL shortener build.

Extend it

  • Colored codes: pass color: { dark: '#1a1a2e', light: '#ffffff' } in the options object.
  • SVG output for crisp printing at any size: use QRCode.toString(text, { type: 'svg' }) and serve it with res.type('image/svg+xml').
  • A form that lets visitors type their own text: post to a route that reads req.body (add app.use(express.urlencoded({ extended: false }))) and redirects to /qr.png?text=....

Adding a package for any of this? Open the Packages page in your server menu, install it, and restart so your app loads it.

Troubleshooting

  • Page won't load / connection refused — the listen call must use SERVER_PORT and 0.0.0.0. See I can't reach my app.
  • Cannot find module 'qrcode' — the install didn't finish. Read the npm install output at the top of the console, or install qrcode from the Packages page and restart.
  • HTTP 400 "Pass ?text=" — you called the endpoint without a text query parameter. Add ?text=something.
  • The image is blank or won't scan — usually too much data crammed into one code, or a rendering size too small. Shorten the text or raise width.

Next steps

Was this guide helpful?