npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-image-transformer

v1.0.0

Published

Self-hosted, Sharp-powered runtime image transforms for Next.js.

Readme

next-image-transformer

Self-hosted, Sharp-powered runtime image transforms for Next.js.

Next.js’s built-in image optimization (next/image + the /_next/image optimizer) is intentionally constrained and opinionated. If you want something closer to “Imgix/Cloudinary, but inside your Next.js app,” this package gives you:

  • A route handler that fetches an upstream image, runs a small set of transforms via Sharp, and caches results on disk.
  • A URL builder that creates transform URLs you can use from your app.

This tends to work best on managed app hosting where you run a Node runtime and can put a CDN in front:

  • DigitalOcean App Platform (CDN-enabled)
  • Render, Fly.io, Railway, Heroku
  • AWS App Runner / ECS / EC2 (often fronted by CloudFront)
  • Google Cloud Run (often fronted by Cloud CDN)
  • Any setup fronted by Cloudflare / Fastly / etc.

Installation (Next.js App Router)

1) Install:

yarn add next-image-transformer sharp

2) Add a route handler

Create a route handler at some path, for example: src/app/image/route.ts

// src/app/api/image/route.ts

import { createImageTransformRouteHandler } from "next-image-transformer/server";

export const runtime = "nodejs";

const handler = createImageTransformRouteHandler({
  // Must be an absolute URL. This is used to build a canonical URL for caching.
  apiRouteUrl:
    process.env.IMAGE_TRANSFORM_API_URL ?? "http://localhost:3000/api/image",
});

export const GET = handler;

3) Create a URL builder module

Create a helper for example: src/lib/imageUrlBuilder.ts

import { createImageUrlBuilder } from "next-image-transformer";

export const imageUrlBuilder = createImageUrlBuilder({
  // Same absolute URL as the route above, but safe to expose publicly
  // if you want to build URLs client-side.
  apiRouteUrl:
    process.env.NEXT_PUBLIC_IMAGE_TRANSFORM_API_URL ??
    "http://localhost:3000/api/image",
});

4) Start writing URLs:

Then build URLs like:

// src/components/MyImage.tsx

import { imageUrlBuilder } from "../lib/imageUrlBuilder";

export function MyImage() {
  return (
    <img
      src={imageUrlBuilder({
        source: "https://images.example.com/cat.jpg",
        fmt: "webp",
        w: 800,
        q: 80,
      })}
    />
  );
}

API reference

createImageTransformRouteHandler(options)

Import from: next-image-transformer/server

Returns: (req: Request) => Promise<Response> (compatible with Next.js Route Handlers)

Options

  • apiRouteUrl: string (required)
    • Description: Absolute URL for the transform route (used to generate a canonical URL for caching).
    • Default: none
  • cacheDir: string (optional)
    • Description: Directory on disk where transformed images are cached.
    • Default: path.join(process.cwd(), ".transform-cache")
  • cacheControl: string (optional)
    • Description: Value for the response Cache-Control header.
    • Default: "public, max-age=31536000, immutable"
  • allowedHosts: Array<string | RegExp> (optional)
    • Description: Allowlist for the upstream source URL host. If omitted, all hosts are allowed.
      • Exact host: "images.example.com"
      • Host + port: "localhost:3000"
      • RegExp: /^(?:.+\.)?example\.com$/ (tested against both hostname and host)
    • Default: undefined (allow all)

Behavior notes

  • Format defaulting: if fmt is omitted in the URL, it defaults to "preserve".
  • Quality defaulting: if q is omitted, the handler uses 100.
  • Resize semantics: if w and/or h is provided, the image is resized with:
    • fit: "inside" (or the provided fit)
    • withoutEnlargement: true
  • Auto-orient: Sharp rotate() is applied to respect EXIF orientation.
  • Caching: responses are cached on disk; your runtime must have a writable filesystem.

createImageUrlBuilder(options)

Import from: next-image-transformer

Returns: a function (config: TransformConfig) => string that builds a transform URL.

Options

  • apiRouteUrl: string (required)
    • Description: Absolute URL for your transform route.
    • Default: none

Transform config + query parameters

The transform URL uses these query params:

  • source: string (required)
    • Absolute http(s) URL to the upstream image.
  • fmt: "preserve" | "webp" | "avif" (optional)
    • If omitted, it defaults to "preserve".
  • w: number (optional)
    • 32-bit integer
  • h: number (optional)
    • 32-bit integer
  • fit: "cover" | "contain" | "fill" | "inside" | "outside" (optional)
    • Only used when resizing (w and/or h is provided)
    • If omitted, it defaults to "inside".
  • q: number (optional)
    • Integer in [0..100]
    • Default: 100

License

See LICENSE.md.