On‑the‑fly WebP/AVIF/JPEG/PNG in Express. Trustworthy, solid, and lightweight.
Add it once and stop worrying about image optimization and edge cases — forever.
const { upflyUpload, upflyConvert } = require('upfly')
upflyUpload({
fields: {
'images': { output: 'memory', format: 'webp', quality: 70 }, //webp version stored in req.files
'HeroImage': { output: 'disk', format: 'webp', quality: 80 }, //webp version saved to disk
'documents': { output: 'disk'} //saved to disk as-is,
},
outputDir: './uploads',
limit: 5 * 1024 * 1024 // 5MB
})
Only pass field names and (optionally) an output directory. Everything else is handled for you.
Defaults: format webp · quality 80 · output memory
upflyUpload({
fields: {
images: {},
avatars: {}
}
})
When any field outputs to disk, files are saved safely under your project
upflyUpload({
fields: { images: { output: 'disk' } },
outputDir: '/uploads' // resolves to <projectRoot>/uploads
})
Under the hood when you only provide field names:
Upload + convert in one step, or keep full control over Multer and convert only
{ upflyUpload } = require('upfly')
app.post('/upload', upflyUpload({
fields: {
'images': { output: 'memory', format: 'webp', quality: 70 }, //webp version stored in req.files
'HeroImage': { output: 'disk', format: 'webp', quality: 80 }, //webp version saved to disk
'documents': { output: 'disk'} //saved to disk as-is,
},
outputDir: './uploads'
}), (req, res) => res.json({ files: req.files }))
const multer = require('multer')
{ upflyConvert } = require('upfly')
const upload = multer({ storage: multer.memoryStorage() })
app.post('/convert',
upload.fields([{ name: 'images', maxCount: 10 }]), // your upload logic
upflyConvert({
fields: {
images: { format: 'webp', quality: 80 } //default saves to the memory(req.file || req.files)
}}),
(req, res) => res.json({ files: req.files }))
You have to manually convert images to WebP before uploading, or set up complex pipelines to handle optimization after upload.
Large unoptimized images kill your site speed. Users bounce, SEO suffers, and conversion rates drop.
Setting up Multer, Sharp, file handling, error management, and different output formats requires tons of boilerplate code.
Upload files and convert images instantly. Memory or disk storage. Multiple formats. Graceful fallbacks. Type-safe. Production-ready.
Convert images to WebP, AVIF, JPEG, or PNG on-the-fly during upload. No separate processing step needed.
If conversion fails, files pass through unchanged. Your app never breaks, users never get stuck.
Store converted buffers in memory for immediate use, or save directly to disk. Your choice, seamlessly handled.
Replace dozens of lines of Multer + Sharp boilerplate with one clean middleware configuration.
Automatically resolves paths safely under your project root. Warns about potential security issues in development.
Ships with TypeScript definitions. Get autocomplete and type safety out of the box.
Install upfly and multer (peer dependency)
Tip: All commands work on Windows, macOS, and Linux — choose the one that matches your package manager.
Note about multer: It's a peer dependency, so you have full control over its version. This prevents conflicts with any existing multer version in your project.
Developer logs: set 'NODE_ENV=development' in your .env file to print conversion details in your terminal.
Here's what YOU write - simple, clean, powerful
Perfect for cloud uploads or immediate processing
upflyUpload({
fields: {
profilePic: { output: 'memory', format: 'webp', quality: 85 },
gallery: { output: 'memory', format: 'avif', quality: 75 }
}
})
Great for static file serving and CDN uploads
upflyUpload({
fields: {
images: { output: 'disk', format: 'webp', quality: 80 },
documents: { output: 'disk' } // Non-images pass through
},
outputDir: './uploads'
})
Different fields, different formats, different outputs
upflyUpload({
fields: {
thumbnails: { output: 'memory', format: 'webp', quality: 60 },
originals: { output: 'disk', format: 'jpeg', quality: 95 },
avatars: { output: 'disk', format: 'avif', quality: 70 }
},
outputDir: './public/uploads',
limit: 10 * 1024 * 1024 // 10MB
})
Use with your own upload setup
// Your existing upload
const upload = multer({ storage: multer.memoryStorage() });
// Just add conversion
upflyConvert({ fields: { images: { format: 'webp', quality: 80 } } })
Here's how it looks in a real Express route
const express = require('express');
const { upflyUpload } = require('upfly');
const app = express();
// Single route handles upload + conversion
app.post('/upload',
upflyUpload({
fields: {
images: { output: 'memory', format: 'webp', quality: 80 },
documents: { output: 'disk' } // PDFs, etc. saved as-is
},
outputDir: './uploads',
limit: 5 * 1024 * 1024 // 5MB limit
}),
(req, res) => {
// Images are now optimized WebP in req.files.images
// Documents are saved to disk in req.files.documents
res.json({ message: 'Upload successful!', files: req.files });
}
);
app.listen(3000);
PDFs, documents, videos pass through unchanged. Only images get converted. No errors, no confusion.
If Sharp fails (corrupted image, unsupported format), original file is returned. Your app keeps running.
Paths like '/uploads' resolve safely under your project root. Warns about potential issues in development.
Output directories are created automatically. No need to manually create folder structures.
Generated filenames include field names, slugified originals, and unique suffixes. No collisions, ever.
Development mode shows before/after file sizes and conversion details. Know exactly what's happening.
Just use "NODE_ENV=development" in your .env file