Skip to main content
Version: 3.72.0

Next.js Image Optimizer

Platformatic Next can run in Image Optimizer mode, where the service exposes only the Next.js image endpoint (/_next/image) instead of starting the full Next.js application.

For a step-by-step setup, see Run Next.js Image Optimizer as a Dedicated Service.

When to use it​

Use this mode when you want a dedicated image optimization service in your runtime, for example:

  • to offload image transformations from frontend services
  • to centralize image optimization and caching behavior
  • to fetch originals from a local Platformatic service via service discovery

Architecture​

When next.imageOptimizer.enabled is true, Platformatic Next:

  1. loads Next.js image parameter validation logic and Next.js configuration
  2. starts a lightweight HTTP server exposing GET /_next/image (or <basePath>/_next/image)
  3. validates query parameters using Next.js internal rules
  4. resolves the source URL:
    • absolute url query values are used as-is
    • relative url query values are resolved against fallback
  5. fetches and optimizes the image through a queue-backed optimizer
  6. returns optimized bytes with content type and cache headers

The queue storage backend can be in-memory, filesystem-based, or Valkey/Redis-based.

Queueing model​

Every image request is processed through a queue-driven pipeline:

  1. a GET /_next/image request is validated by Next.js parameter rules
  2. the optimizer creates queue work for fetch + transform
  3. a worker executes optimization with a timeout budget (timeout)
  4. failures are retried up to maxAttempts
  5. the result is returned to the client or a 502 is returned when retries are exhausted

Why this matters:

  • it avoids tying optimization throughput directly to frontend request spikes
  • it gives you explicit retry/timeout controls for unstable upstream sources
  • it lets you choose storage based on runtime topology:
    • memory for local/dev or single-instance setups
    • filesystem for single-node persistence on disk
    • redis/valkey for multi-instance and shared queue state

Configuration​

Enable Image Optimizer mode in watt.json (or platformatic.json):

{
"$schema": "https://schemas.platformatic.dev/@platformatic/next/3.38.1.json",
"next": {
"imageOptimizer": {
"enabled": true,
"fallback": "frontend",
"timeout": 30000,
"ttl": 3600000,
"maxAttempts": 3
}
}
}

In this example:

  • enabled: true turns on Image Optimizer mode, so this service only serves the image endpoint.
  • fallback: "frontend" means relative url values (for example /images/photo.jpg) are fetched from http://frontend.plt.local/images/photo.jpg through Platformatic service discovery.
  • timeout: 30000 sets a 30 second timeout for fetch/optimization jobs.
  • ttl: 3600000 sets a 1 hour TTL for jobs results.
  • maxAttempts: 3 retries failed optimization jobs up to 3 times before returning an error.

If you do not set storage, Platformatic uses in-memory queue storage by default.

Exposing Image Optimizer through Gateway (proxy.routes)​

A common production setup is to keep Gateway as runtime entrypoint and route only /_next/image traffic to the optimizer service.

services/gateway/platformatic.json:

{
"$schema": "https://schemas.platformatic.dev/@platformatic/gateway/3.0.0.json",
"gateway": {
"applications": [
{
"id": "frontend",
"proxy": {
"prefix": "/"
}
},
{
"id": "optimizer",
"proxy": {
"prefix": "/",
"routes": ["/_next/image"],
"methods": ["GET"]
}
}
]
}
}

This routes image optimization requests to optimizer, while all other requests are handled by frontend.

Configuration options​

  • enabled: Boolean flag to enable Image Optimizer mode. Default: false.
  • fallback: Source used to fetch original images when the request URL is relative:
    • A full URL (for example, https://cdn.example.com)
    • A local service name (for example, frontend), resolved as http://frontend.plt.local
  • storage: Queue storage backend:
    • { "type": "memory" } (default)
    • { "type": "filesystem", "path": "./.next/cache/image-optimizer" }
    • { "type": "valkey", "url": "redis://localhost:6379", "prefix": "my-app:", "db": 0 } (or redis)
      • prefix maps to the Redis/Valkey key prefix used by the queue storage.
      • db selects the Redis/Valkey logical database index.
  • timeout (number or string): Request/job timeout in milliseconds. Default: 30000.
  • ttl: (number or string): Job result TTL in milliseconds. Default: 3600000 (1 hour)
  • maxAttempts (number or string): Maximum retry attempts for optimization jobs. Default: 3.

Endpoint​

The service exposes the standard Next.js image endpoint:

GET /_next/image?url={imageUrl}&w={width}&q={quality}

If application.basePath is configured, the endpoint is prefixed accordingly (for example /frontend/_next/image).

Query parameters​

  • url: Image URL to optimize:
    • Absolute URL for external images (for example, https://example.com/image.png)
    • Relative path for internal images (for example, /images/photo.jpg)
  • w: Desired width in pixels
  • q: Quality value accepted by Next.js optimizer (as validated by Next.js)

Error handling​

The optimizer returns 502 Bad Gateway for optimization failures, including upstream fetch errors and invalid optimization parameters.

Example response:

{
"error": "Bad Gateway",
"message": "An error occurred while optimizing the image.",
"statusCode": 502,
"cause": {
"message": "Invalid optimization parameters.",
"reason": "\"q\" parameter (quality) of 10 is not allowed"
}
}