OptStuff

Usage Scenarios

Choose the best OptStuff signing and caching strategy for fixed image blocks, frequently changing content blocks, and user-triggered dynamic image requests.

The hard part of image optimization is usually not "can we optimize images?" but "which signing and caching strategy should we use for each UI pattern?"

This guide maps OptStuff to three common scenarios:

  1. Fixed image blocks (rarely changes)
  2. Frequently changing blocks (updates regularly, but not on every interaction)
  3. User-triggered dynamic blocks (new image requests generated after user actions)

Core Principle

OptStuff URLs are content-addressable:

  • same input parameters -> same URL
  • same URL -> same output
  • different parameters or exp -> different cache key

Because of this property, long-lived caching is safe when your URL shape remains stable.

Scenario Matrix

ScenarioTypical ExampleChange FrequencyRecommended Signing LocationRecommended exp StrategyPrimary Goal
Fixed image blockHero image, brand visuals, long-lived campaign assetsLowServer Component / backend renderLong TTL (24h to 7d) or versioned URLMax cache hit ratio and stable LCP
Frequently changing blockProduct cards, article lists, rotating bannersMediumAPI Route or backendBucketed exp (hour/day windows)Balance freshness and cache efficiency
User-triggered dynamic blockFiltered galleries, interactive previews, personalized recommendationsEvent-drivenAPI Route (with auth + validation)Short TTL (1-10 min)Fast response with abuse protection

Decision Flow

Scenario A: Fixed Image Block

Use this for above-the-fold hero images, brand assets, and other images that rarely change.

Recommended pattern:

  • sign URLs in Server Components or backend templates
  • use a longer validity window (exp)
  • keep URL shape deterministic (avoid random params)
  • preload the primary hero image (preload, or priority on older Next.js versions)

Why this works:

  • stable URLs -> better CDN/browser reuse
  • fewer runtime signing requests
  • more consistent LCP performance

Scenario B: Frequently Changing Block

Use this when content updates regularly, but not on every click.

Recommended pattern:

  • sign in API Routes or backend services
  • use bucketed expiration (for example, hourly windows)
  • standardize width breakpoints to reduce URL variants
  • keep operation presets consistent across similar components

Common anti-pattern:

  • generating exp = now + ttl on every render creates a new URL each time and severely hurts cache hit ratio

Scenario C: User-Triggered Dynamic Block

Use this when new image requests are created after explicit user actions (filtering, mode switches, live previews, personalization).

Recommended pattern:

  • frontend calls your API Route to request signed URLs
  • API Route verifies session/token
  • API Route validates input (w, h, q, f, source host)
  • API Route applies rate limiting and short exp
  • frontend uses debounce/abort to avoid bursty duplicate requests

Security baseline:

  • never expose OPTSTUFF_SECRET_KEY in client bundles
  • never allow signing endpoints to become unauthenticated open oracles

End-to-End Request Flow

Suggested Defaults

ParameterFixed blockFrequently changing blockUser-triggered block
exp24h-7d1h-24h bucketed1-10m
Signing locationServer renderAPI Route / backendAPI Route with auth
Cache focusMaximum reuseReuse + bounded freshnessControlled freshness
Risk controlsVersioned URLsBucketing + width standardizationAllowlist + rate limit + auth

Pre-Launch Checklist

  • secret key is server-only and never exposed in browser code
  • signing logic runs only in Server Components or API Routes
  • source-domain allowlist is configured
  • operation parameter validation exists in app-side API Route
  • exp strategy matches each scenario
  • common widths are standardized to prevent URL explosion
  • CDN hit headers are monitored (cf-cache-status, x-vercel-cache, x-cache)

Last updated on

On this page