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.pngis just a URL, you can embed live QR codes anywhere:<img src="https://YOUR_ADDRESS:PORT/qr.png?text=YOUR_LINK">. Change thetextand 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 setres.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 base64data: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 withres.type('image/svg+xml'). - A form that lets visitors type their own text: post to a route that reads
req.body(addapp.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
listencall must useSERVER_PORTand0.0.0.0. See I can't reach my app. Cannot find module 'qrcode'— the install didn't finish. Read thenpm installoutput at the top of the console, or installqrcodefrom the Packages page and restart.- HTTP 400 "Pass ?text=" — you called the endpoint without a
textquery 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
- Build an image resize API
- Build a URL shortener
- Put it on a real domain with HTTPS
- The
qrcodepackage's full options are documented on the node-qrcode project page.