Automate Image Optimization in Express.js with the ShortPixel Middleware

If you are building an Express.js application that handles images, whether users are uploading avatars, providing image URLs, or processing local server files, you already know the drill.

You have to parse the request, buffer the file, send it to an optimization service, wait for the result, and then pass it along to your storage logic.

In our previous guide, we covered the core ShortPixel Node SDK, which gives you absolute control over this process.

But what if you don’t want to orchestrate all that logic inside every single route handler?

Learn more about ShortPixelExpress – the official Express middleware layer for the ShortPixel Node SDK.

Instead of manually wiring up API calls in your controllers, ShortPixelExpress acts as a request adapter. You mount it before your route handler, and it automatically intercepts supported images, optimizes them, and hands your route handler a request object populated with fully optimized buffers and normalized metadata.

Let’s look at how to set it up and how it handles the three most common image processing scenarios in Express.

Getting started

The middleware is bundled with the official package. It is ESM-only, so ensure your project has "type": "module" in its package.json and runs on Node 20 or higher.

npm i @shortpixel-com/shortpixel

To initialize it, you just need your API key and your preferred optimization settings (like lossy compression or WebP/AVIF conversion).

import { ShortPixelExpress } from "@shortpixel-com/shortpixel";

const optimizeImages = ShortPixelExpress({
  apiKey: process.env.SHORTPIXEL_API_KEY,
  lossy: 1,           // 1 = Lossy compression
  convertto: "+webp", // Automatically generate WebP
});

Note: The middleware doesn’t parse multipart forms or JSON bodies itself. You still need to mount your standard parsers like multer or express.json() before it.

3 ways the middleware automates your workflow

The beauty of ShortPixelExpress is that it handles the exact input format you throw at it and mutates the request intelligently.

1. Intercepting uploaded files (Multer)

If you are accepting user uploads via multer, the middleware reads req.file or req.files. If the file is in memory, it optimizes it and replaces the buffer in place. If it’s on disk, it writes the optimized bytes back to disk and updates the file path.

By the time the request hits your controller, req.file.buffer is already optimized.

import express from "express";
import multer from "multer";
import { ShortPixelExpress } from "@shortpixel-com/shortpixel";

const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post(
  "/upload",
  upload.single("image"),
  ShortPixelExpress({
    apiKey: process.env.SHORTPIXEL_API_KEY,
    lossy: 1,
    convertto: "+webp",
  }),
  (req, res) => {
    // req.file.buffer is ALREADY the optimized WebP buffer!
    const result = req.shortPixel?.files?.[0];

    res.json({
      optimizedFilename: req.file?.originalname,
      resultFilename: result?.filename,
      savedToRequest: !!req.file?.buffer,
    });
  }
);

2. Processing remote URLs from req.body

Sometimes your users submit a URL instead of a file. The middleware scans the request body for standard whitelisted keys (like url or urls). If it finds a valid HTTPS URL, it optimizes the remote image and attaches the result directly to req.shortPixel.urls.

app.use(express.json());

app.post(
  "/from-url",
  ShortPixelExpress({
    apiKey: process.env.SHORTPIXEL_API_KEY,
    lossy: 1,
  }),
  (req, res) => {
    // The original req.body.url is untouched, but the optimized result is ready
    const result = req.shortPixel?.urls?.[0];

    res.json({
      sourceUrl: result?.input,
      filename: result?.filename,
      optimizedBytes: result?.buffer?.length,
    });
  }
);

3. Optimizing local file paths

If you pass local filesystem paths in the request body (e.g., req.body.imagePath), the middleware optimizes the file, writes it next to the original file, and mutates the req.body value to point to the new optimized path.

app.post(
  "/from-path",
  ShortPixelExpress({
    apiKey: process.env.SHORTPIXEL_API_KEY,
    extraWhitelist: ["coverPath"], // Tell it to look for this specific key
  }),
  (req, res) => {
    const result = req.shortPixel?.paths?.[0];

    res.json({
      originalPath: result?.input,
      optimizedPath: req.body.coverPath, // This has been automatically updated!
      filename: result?.filename,
    });
  }
);

Global middleware & the passthrough option

If you don’t want to attach the middleware to every single image-heavy route, you can mount it globally using the passthrough: true option.

This tells the middleware: “If a request doesn’t contain any image files or matching fields, just skip it and let it proceed normally.” Furthermore, the middleware automatically skips uploads and local files smaller than 50KB to save your quota and processing time.

app.use(
  ShortPixelExpress({
    apiKey: process.env.SHORTPIXEL_API_KEY,
    passthrough: true, // Let non-image requests pass through without throwing errors
    lossy: 1,
  })
);

Summary

If the core ShortPixel SDK is the engine, ShortPixelExpress is the automatic transmission. It inspects the request, optimizes whatever matches, and hands you the normalized results right on the Express request object.

Ready to drop it into your stack? Check out the full documentation on GitHub for a deep dive into custom field matching, metadata extraction, and advanced error handling.

Andrei Alba
Andrei Alba

Andrei Alba is a support specialist and writer here at ShortPixel. He enjoys helping people understand WordPress through his easily digestible materials.

Articles: 99