qr-image, qr.js, and qrcode are libraries used to generate QR codes within JavaScript environments. qrcode is the modern standard, supporting both Node.js and browsers with multiple output formats like Canvas, SVG, and PNG. qr-image focuses on server-side image generation using Node.js streams. qr.js is a legacy library that provides basic encoding capabilities but lacks active maintenance and modern features. Choosing the right tool depends on your deployment environment and output requirements.
Generating QR codes is a common requirement for sharing URLs, payment info, or authentication tokens in web apps. While qr-image, qr.js, and qrcode all claim to solve this problem, they differ significantly in environment support, output formats, and maintenance status. Let's break down how they handle real-world engineering tasks.
qrcode works everywhere.
// qrcode: Works in Node and Browser
import QRCode from 'qrcode';
// Browser
QRCode.toCanvas(element, 'https://example.com');
// Node
QRCode.toDataURL('https://example.com');
qr-image is for Node.js only.
// qr-image: Node.js only
var qr = require('qr-image');
// Generates a buffer
var img = qr.imageSync('https://example.com', { type: 'png' });
qr.js is primarily legacy Node or old browser scripts.
// qr.js: Legacy support
var QRCode = require('qr.js');
// Basic generation
var qr = QRCode.generate('https://example.com');
qrcode gives you multiple formats out of the box.
// qrcode: Multiple formats
import QRCode from 'qrcode';
// SVG String
const svg = await QRCode.toString('text', { type: 'svg' });
// Canvas
await QRCode.toCanvas(canvasElement, 'text');
qr-image focuses on image buffers.
// qr-image: Image buffers
var qr = require('qr-image');
// PNG Buffer
var pngBuffer = qr.imageSync('text', { type: 'png' });
// SVG Buffer
var svgBuffer = qr.imageSync('text', { type: 'svg' });
qr.js has limited output options.
// qr.js: Limited output
var QRCode = require('qr.js');
// Returns module data, not an image
var qrData = QRCode.generate('text');
// Developer must draw this manually
qrcode uses Promises for async operations.
async/await code.// qrcode: Async/Await
try {
const dataUrl = await QRCode.toDataURL('text');
console.log(dataUrl);
} catch (err) {
console.error(err);
}
qr-image offers synchronous methods.
// qr-image: Synchronous
try {
var buffer = qr.imageSync('text');
// Write buffer to file
} catch (err) {
console.error(err);
}
qr.js is synchronous and blocking.
// qr.js: Synchronous
var qr = QRCode.generate('text');
// Runs immediately on main thread
qrcode is actively maintained.
// qrcode: Current standard
// npm install qrcode
// Regularly updated on npm registry
qr-image sees infrequent updates.
// qr-image: Legacy status
// npm install qr-image
// Last major updates were years ago
qr.js is effectively deprecated.
// qr.js: Deprecated
// npm install qr.js
// Considered obsolete by community standards
You need to show a QR code inside a React component.
qrcode// qrcode in React
useEffect(() => {
QRCode.toCanvas(canvasRef.current, url);
}, [url]);
Your backend needs to return a PNG file for download.
qr-image or qrcodeqrcode is safer long-term.// qrcode in Express
app.get('/qr', async (req, res) => {
const dataUrl = await QRCode.toDataURL(req.query.text);
res.send(dataUrl);
});
You are building static HTML files with embedded QR codes.
qrcode// qrcode for SSG
const svg = await QRCode.toString(url, { type: 'svg' });
fs.writeFileSync('index.html', `<body>${svg}</body>`);
| Feature | qrcode | qr-image | qr.js |
|---|---|---|---|
| Environment | π Node + Browser | π₯οΈ Node Only | πΈοΈ Legacy/Both |
| Formats | π¨ Canvas, SVG, PNG | πΌοΈ PNG, SVG Buffers | π Data Matrix |
| API Style | β‘ Async/Promises | π Sync | π Sync |
| Maintenance | β Active | β οΈ Low | β Deprecated |
| Ease of Use | π’ High | π‘ Medium | π΄ Low |
qrcode is the clear winner for modern development. It handles both server and client needs without forcing you to switch libraries. The async API keeps your app responsive, and the variety of output formats saves you from writing extra conversion code.
qr-image is acceptable if you are maintaining an older Node.js service that relies on buffer streams. However, for any new microservice or API, qrcode offers better future-proofing.
qr.js should be avoided. It lacks the features and support needed for professional applications. Migrating to qrcode is a small effort that removes significant technical debt.
Final Thought: Stick with qrcode for reliability. It is the standard tool that lets you focus on building features instead of fixing library issues.
Choose qr-image if you are building a Node.js server application that needs to stream image buffers directly. It is suitable for backend services generating PNG or SVG files for download. Avoid this package for client-side browser applications since it relies on Node-specific modules.
Avoid qr.js for new projects because it is considered legacy and lacks active maintenance. It may work for simple scripts but does not support modern output formats like SVG or Canvas reliably. Evaluate qrcode instead for better long-term support and feature coverage.
Choose qrcode for most modern projects because it works in both Node.js and browsers. It supports multiple output formats like Canvas, SVG, and data URLs without extra dependencies. This package is actively maintained and offers a consistent API across different environments.
This is yet another QR Code generator.
png, svg, eps and pdf formats;npm install qr-image
Example:
var qr = require('qr-image');
var qr_svg = qr.image('I love QR!', { type: 'svg' });
qr_svg.pipe(require('fs').createWriteStream('i_love_qr.svg'));
var svg_string = qr.imageSync('I love QR!', { type: 'svg' });
qr = require('qr-image')
qr.image(text, [ec_level | options]) β Readable stream with image data;qr.imageSync(text, [ec_level | options]) β string with image data. (Buffer for png);qr.svgObject(text, [ec_level | options]) β object with SVG path and size;qr.matrix(text, [ec_level]) β 2D array.text β text to encode;ec_level β error correction level. One of L, M, Q, H. Default M.options β image options object:
ec_level β default M.type β image type. Possible values png (default), svg, pdf and eps.size (png and svg only) β size of one module in pixels. Default 5 for png and undefined for svg.margin β white space around QR image in modules. Default 4 for png and 1 for others.customize (only png) β function to customize qr bitmap before encoding to PNG.parse_url (experimental, default false) β try to optimize QR-code for URLs.zlib.deflateSync instead of pako.