On this page

Images

Optional image optimization with rebaskImage() and <Image>.

Image plugin setup

Install sharp, which the built-in handler uses:

pnpm add sharp

Add rebaskImage() to your Vite plugins:

// vite.config.ts
import { rebaskImage } from "@rebask/core/vite/image"

plugins: [rsc(), react(), rebask(), rebaskImage()]

Create rebask.image.ts at the project root:

// rebask.image.ts
import { handleImage } from "@rebask/core/image"
import sharp from "sharp"

export default function handler(request: Request) {
  return handleImage(request, sharp)
}

Local images are read from public/. Remote URLs must match a remotePatterns entry, and localPatterns can restrict local paths.

Adapters can provide their own image optimization. For example, vercelAdapter() routes /_rebask/image to Vercel's optimizer when rebaskImage() is configured. In that setup, you don't need rebask.image.ts or Sharp.

<Image>

Use width and height for fixed-size images:

import { Image } from "@rebask/core/components/image"

<Image src="/hero.jpg" alt="Storefront" width={1200} height={600} preload />
<Image src="/product.jpg" alt="Product" width={800} height={800} />

Add sizes for responsive images. It tells the browser how wide the image will render:

<Image
  src="/hero.jpg"
  alt="Storefront"
  width={1200}
  height={600}
  sizes="(min-width: 1200px) 1200px, 100vw"
/>

Static imports

Import an image and pass it as src. Static imports are optimized through the handler like other local images, and their dimensions are read at build time, so width and height are not needed:

import hero from "./hero.jpg"

<Image src={hero} alt="Storefront" placeholder="blur" />

placeholder="blur" uses sharp to generate the blur at build time. Without sharp, pass blurDataURL to <Image>.

Static imports are not subject to localPatterns.

Fill

fill makes the image cover a positioned parent. Give the parent dimensions:

<div style={{ position: "relative", width: "100%", aspectRatio: "2 / 1" }}>
  <Image
    src="/hero.jpg"
    alt="Storefront"
    fill
    sizes="(min-width: 1200px) 1200px, 100vw"
  />
</div>

<Image> props

Prop
srcPath or URL
altRequired
width / heightRequired unless fill
sizesRendered width, used for responsive images
fillFill the positioned parent
quality1–100, snapped to the configured qualities
preloadPreload the image
loading"lazy" | "eager"
placeholder"blur" | "empty" | data URL
blurDataURLRequired with placeholder="blur"
unoptimizedSkip optimization
loaderCustom loader

SVG, data:, and blob: URLs are not optimized. The handler rejects SVG unless dangerouslyAllowSVG is enabled. Other <img> attributes, such as className, style, fetchPriority, and onLoad, are passed through.

rebaskImage() options

These are the defaults:

rebaskImage({
  deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
  path: "/_rebask/image",
  qualities: [75],
  formats: ["image/webp"],
  contentSecurityPolicy: "script-src 'none'; frame-src 'none'; sandbox;",
  contentDispositionType: "attachment",
  minimumCacheTTL: 14400,
  unoptimized: false,
  localPatterns: undefined,
  remotePatterns: [],
  dangerouslyAllowSVG: false,
  dangerouslyAllowLocalIP: false,
  maximumRedirects: 3,
  maximumResponseBody: 50000000, // 50 MB
  maximumCacheSize: 50000000, // 50 MB
  handler: "rebask.image.ts",
})
  • deviceSizes sets the widths used for responsive images.
  • imageSizes sets the widths used for fixed-size images.
  • path sets the endpoint and the URLs generated by <Image>.
  • qualities sets the allowed quality values. Other values snap to the closest one.
  • formats sets the formats offered to clients that advertise support.
  • contentSecurityPolicy sets the CSP header on image responses.
  • contentDispositionType sets inline or attachment on image responses.
  • minimumCacheTTL sets the minimum cache lifetime for public images. A longer upstream Cache-Control wins.
  • unoptimized disables optimization for all images.
  • localPatterns limits which files under public/ can be optimized. Leave it undefined to allow all local images.
  • remotePatterns lists the remote URLs the server may fetch. No remote images are allowed by default.
  • dangerouslyAllowSVG serves SVG images instead of rejecting them. Only enable it for trusted sources.
  • dangerouslyAllowLocalIP allows remote images from private or loopback addresses. Leave it false to block SSRF.
  • maximumRedirects sets how many redirects a remote image may follow.
  • maximumResponseBody caps the remote image size in bytes.
  • maximumCacheSize caps the in-memory image cache in bytes. Caching is disabled in development.
  • handler sets the handler file. Rebask also detects rebask.image.js.

Image caching

Optimized images are cached in memory in production. The handler follows the upstream Cache-Control header:

  • no-store and private responses bypass the shared cache. private responses stay private to the browser.
  • no-cache and max-age=0 responses bypass the shared cache and are returned with max-age=0, must-revalidate.
  • s-maxage and max-age set the cache lifetime, with minimumCacheTTL as the floor for public images with a positive max age.

Remote patterns

Remote images need an entry in remotePatterns:

rebaskImage({
  remotePatterns: [
    { hostname: "images.example.com", pathname: "/products/**" },
    { protocol: "https", hostname: "*.cdn.example.com" },
  ],
})

Each pattern can set protocol, hostname, port, pathname, and search. hostname is required. Patterns match the whole value.

  • * matches a single segment, such as one subdomain or one path segment.
  • ** matches any number of segments.
  • search matches the query string exactly, including ?. An empty string matches no query string.
  • When protocol, port, pathname, or search is omitted, any value matches.

localPatterns uses the same pathname and search rules:

rebaskImage({
  localPatterns: [
    { pathname: "/images/**" },
    { pathname: "/products/*.jpg", search: "" },
  ],
})