
Research
/Security News
npm Author Qix Compromised via Phishing Email in Major Supply Chain Attack
npm author Qix’s account was compromised, with malicious versions of popular packages like chalk-template, color-convert, and strip-ansi published.
discord-multiimage
Advanced tools
Display multiple images in Discord with grid or stacked layouts.
Transform messy Discord image spam into beautiful, unified galleries
The zero-friction way to send multiple images in Discord without the clutter
Discord bots that send multiple images create visual chaos:
🤖 Bot: Here are your results!
[Embed 1: Single image with title]
[Embed 2: Single image with title]
[Embed 3: Single image with title]
[Embed 4: Single image with title]
Result: Cluttered chat, repetitive titles, inconsistent spacing, poor mobile experience.
discord-multiimage creates native-looking galleries that feel like Discord designed them:
🤖 Bot: Here are your results!
[Single unified embed with 4 images in perfect grid layout]
Result: Clean, professional, mobile-friendly image presentations.
npm install discord-multiimage
Ideal for displaying 2–4 images in a single unified layout.
const { mergeImagesInGrid } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');
const imageUrls = [
'https://example.com/screenshot1.png',
'https://example.com/screenshot2.png',
'https://example.com/screenshot3.png'
];
const { file, imageUrl } = await mergeImagesInGrid(imageUrls);
const embed = new EmbedBuilder()
.setTitle('Game Screenshots')
.setImage(imageUrl)
.setColor('#5865F2');
await interaction.reply({ embeds: [embed], files: [file] });
Great for scrollable galleries like art portfolios or product shots.
const { buildStackedImageData } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');
const { imageUrls, invisibleTitle, groupUrl } = buildStackedImageData([
'https://example.com/art1.jpg',
'https://example.com/art2.jpg',
'https://example.com/art3.jpg'
], {
groupUrl: 'https://portfolio.example.com' // Required for grouping
});
const embeds = imageUrls.map(url =>
new EmbedBuilder()
.setTitle(invisibleTitle) // Invisible but needed for Discord to group (Optional: You can use any title yet it will appear as a link)
.setURL(groupUrl)
.setImage(url)
.setColor('#FF6B6B')
);
await channel.send({ embeds });
Use createMultiImageData() to let your bot dynamically choose layout style.
const { createMultiImageData } = require('discord-multiimage');
const { EmbedBuilder } = require('discord.js');
const result = await createMultiImageData({
mode: 'grid', // or 'stacked'
imageUrls: ['https://example.com/img1.png', 'https://example.com/img2.png'],
options: {
spacing: 6,
backgroundColor: '#2f3136'
}
});
if (result.file) {
const embed = new EmbedBuilder().setImage(result.imageUrl);
await interaction.reply({ embeds: [embed], files: [result.file] });
} else {
const embeds = result.imageUrls.map(url =>
new EmbedBuilder().setImage(url).setURL(result.groupUrl).setTitle('\u200B')
);
await channel.send({ embeds });
}
| 2 Images | 3 Images | 4 Images |
|---|---|---|
| Side-by-side (16:9 ratio) | Large + Stack (4:3 ratio) | Perfect Grid (1:1 ratio) |
![]() | ![]() ![]() | ![]() ![]() |
| ❌ Without discord-multiimage | ✅ With discord-multiimage |
|---|---|
|
|
const { file, imageUrl } = await mergeImagesInGrid(urls, {
spacing: 4, // Pixels between images (default: 2)
maxWidth: 800, // Maximum canvas width (default: 600)
backgroundColor: '#36393f', // Canvas background color
cornerRadius: 8 // Rounded corners for images
});
const { imageUrls, invisibleTitle, groupUrl } = buildStackedImageData(urls, {
groupUrl: 'https://your-site.com/gallery', // Required for grouping
titleText: '\u200B' // Custom invisible character (default: zero-width space)
});
// Show match highlights in one clean embed
const highlights = await mergeImagesInGrid([
killcam1, killcam2, scoreboard, playerStats
]);
// Create scrollable art galleries
const gallery = buildStackedImageData(artworkUrls, {
groupUrl: 'https://artist.portfolio.com'
});
// Combine multiple chart screenshots
const dashboard = await mergeImagesInGrid([
salesChart, trafficChart, conversionChart
]);
// Product image galleries
const productGallery = buildStackedImageData([
mainPhoto, sideView, detailShot, packagingPhoto
]);
| Scenario | Recommended Mode | Why |
|---|---|---|
| Screenshots to compare side-by-side | Grid | Visual comparison is easier |
| Art portfolio or photo gallery | Stacked | Users want to focus on each image |
| Dashboard with multiple charts | Grid | Overview of all metrics at once |
| Step-by-step tutorial images | Stacked | Sequential viewing preferred |
| Before/after comparisons | Grid | Direct visual comparison |
| Large collection (5+ images) | Stacked | Grid limited to 4 images max |
discord.js v14+skia-canvas (faster than node-canvas)Problem: Embeds appear separately instead of grouped.
// Missing required URL
.setURL(groupUrl) // ← This is required for grouping!
Problem: Large images taking too long to process.
// Optimize with smaller max width
await mergeImagesInGrid(urls, { maxWidth: 400 });
Problem: Images don't scale properly on small screens.
// Discord handles this automatically with our layouts!
// No additional code needed - it just works ✨
We love contributions! Here's how to get started:
git clone https://github.com/sajidurdev/discord-multiimage.gitnpm installgit checkout -b amazing-featuregit clone https://github.com/sajidurdev/discord-multiimage.git
cd discord-multiimage
npm install
npm test
MIT © sajidurdev
Free to use in any project - commercial or open source. Attribution appreciated but not required.
Made with ❤️ for the Discord community
📚 Usage Guide • 🐛 Report Bug • 💡 Request Feature • 💬 Discord Server
⭐ Star this repo if it helped you build better Discord bots! ⭐
FAQs
Display multiple images in Discord with grid or stacked layouts.
The npm package discord-multiimage receives a total of 1 weekly downloads. As such, discord-multiimage popularity was classified as not popular.
We found that discord-multiimage demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
npm author Qix’s account was compromised, with malicious versions of popular packages like chalk-template, color-convert, and strip-ansi published.

Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.

Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.