How to Generate QR Codes in Node.js (3 Methods)
QR codes are everywhere: restaurant menus, payment systems, marketing campaigns. If you're building with Node.js, you have several options for generating them.
In this tutorial, you'll learn three approaches, from a simple npm package to a production-ready API.
Method 1: The qrcode Package
The qrcode package is the most popular choice for basic QR code generation. It's free, simple, and works well for most use cases.
Installation
npm install qrcode
Basic Usage
Generate a QR code as a data URL (useful for embedding in HTML):
const QRCode = require('qrcode');
async function generateQR(text) {
try {
const dataUrl = await QRCode.toDataURL(text);
console.log(dataUrl);
// Returns: data:image/png;base64,iVBORw0KGgo...
} catch (err) {
console.error(err);
}
}
generateQR('https://example.com');
Save to File
const QRCode = require('qrcode');
async function saveQR(text, filepath) {
try {
await QRCode.toFile(filepath, text);
console.log('QR code saved to', filepath);
} catch (err) {
console.error(err);
}
}
saveQR('https://example.com', './qrcode.png');
Customization Options
The package supports colors and error correction:
const QRCode = require('qrcode');
const options = {
errorCorrectionLevel: 'H', // L, M, Q, H (highest)
type: 'png',
width: 512,
margin: 2,
color: {
dark: '#000000',
light: '#ffffff'
}
};
async function generateCustomQR(text) {
const dataUrl = await QRCode.toDataURL(text, options);
return dataUrl;
}
Pros and Cons
Pros:
- Free and open source
- No external dependencies
- Works offline
- Good for simple use cases
Cons:
- No analytics or tracking
- No URL shortening
- You handle storage yourself
- Can't update destination after generation
Method 2: Canvas-Based Approach
For more control over the output, you can use the canvas package with qrcode:
npm install qrcode canvas
This approach gives you pixel-level control:
const QRCode = require('qrcode');
const { createCanvas } = require('canvas');
async function generateWithCanvas(text) {
const canvas = createCanvas(512, 512);
await QRCode.toCanvas(canvas, text, {
width: 512,
margin: 2,
color: {
dark: '#1a1a2e',
light: '#ffffff'
}
});
// Now you can manipulate the canvas
const ctx = canvas.getContext('2d');
// Add a logo in the center (optional)
// const logo = await loadImage('./logo.png');
// ctx.drawImage(logo, 206, 206, 100, 100);
return canvas.toBuffer('image/png');
}
When to Use Canvas
- You need to add logos or watermarks
- You want custom shapes or effects
- You're generating images for specific platforms
- You need precise control over output quality
Method 3: QRStar API (Production)
For production applications, an API offers advantages that libraries can't match:
- Analytics: Track scans automatically
- Dynamic URLs: Change destinations without regenerating
- CDN delivery: Fast, global image delivery
- No storage management: We handle it
Basic API Call
async function generateWithAPI(url) {
const response = await fetch('https://api.qrstar.app/v1/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.QRSTAR_API_KEY
},
body: JSON.stringify({
data: url,
size: 512,
format: 'png'
})
});
const { qr_code_url } = await response.json();
return qr_code_url;
}
// Usage
const qrUrl = await generateWithAPI('https://example.com');
console.log(qrUrl); // https://cdn.qrstar.app/abc123.png
Dynamic QR Codes with Tracking
The real power is in dynamic codes:
async function generateDynamicQR(redirectUrl) {
const response = await fetch('https://api.qrstar.app/v1/generate/dynamic', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.QRSTAR_API_KEY
},
body: JSON.stringify({
redirect_url: redirectUrl,
expires_at: '2025-12-31T23:59:59Z'
})
});
const data = await response.json();
return {
qrCodeUrl: data.qr_code_url, // The QR code image
shortUrl: data.short_url, // Trackable short URL
analyticsId: data.analytics_id // For fetching scan data
};
}
Fetching Analytics
async function getAnalytics(analyticsId) {
const response = await fetch(
`https://api.qrstar.app/v1/analytics/${analyticsId}`,
{
headers: {
'X-API-Key': process.env.QRSTAR_API_KEY
}
}
);
const data = await response.json();
console.log(`Total scans: ${data.analytics.total_scans}`);
console.log(`Devices:`, data.analytics.devices);
console.log(`Scans by day:`, data.analytics.scans_by_day);
}
Which Method Should You Use?
Use the qrcode package when:
- You're prototyping or learning
- You don't need analytics
- Your codes will never change
- You want zero external dependencies
Use canvas when:
- You need custom styling or logos
- You're generating images for specific formats
- You want pixel-level control
Use an API when:
- You need scan analytics
- URLs might change after printing
- You're building a production app
- You want CDN-delivered images
- You don't want to manage storage
Production Considerations
Whichever method you choose, consider these for production:
Error Handling
async function generateQRSafe(text) {
try {
const result = await generateQR(text);
return { success: true, data: result };
} catch (error) {
console.error('QR generation failed:', error.message);
return { success: false, error: error.message };
}
}
Caching
If you're generating the same codes repeatedly, cache them:
const cache = new Map();
async function generateWithCache(text) {
if (cache.has(text)) {
return cache.get(text);
}
const qrCode = await generateQR(text);
cache.set(text, qrCode);
return qrCode;
}
Rate Limiting
If using an API, respect rate limits:
const pLimit = require('p-limit');
const limit = pLimit(10); // 10 concurrent requests max
async function batchGenerate(urls) {
const promises = urls.map(url =>
limit(() => generateWithAPI(url))
);
return Promise.all(promises);
}
Summary
| Method | Best For | Cost | Analytics |
|---|---|---|---|
| qrcode package | Learning, prototypes | Free | No |
| Canvas approach | Custom styling | Free | No |
| QRStar API | Production apps | Pay-per-use | Yes |
Start with the qrcode package to learn the basics. When you need analytics or dynamic URLs, switch to an API.
Ready to add analytics to your QR codes? Get your free API key and start tracking scans today.