All Docs
FeaturesDepositClearUpdated March 11, 2026

Image Optimisation with next/image

Image Optimisation with next/image

Status: Remediation tracked under PERF-02. No images are currently rendered via raw <img> tags, but this guide establishes the standard for all future image work.

Background

The current application stores property photos as S3 keys and does not render them directly in the UI. However, as the product expands to include features like property photo galleries in check-in/check-out reports, using raw <img> tags would introduce measurable performance regressions.

Next.js ships a built-in <Image> component that provides:

Feature<img>next/image
WebP / AVIF conversion✓ (automatic)
Lazy loading✓ (default)
Responsive srcset✓ (automatic)
Layout shift prevention (CLS)✓ (reserved space)
Remote domain allowlisting✓ (via remotePatterns)

Configuration

Before serving images from the S3 bucket, add the domain to next.config.ts:

// next.config.ts
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: new URL(process.env.NEXT_PUBLIC_STORAGE_URL!).hostname,
      },
    ],
  },
};

export default nextConfig;

NEXT_PUBLIC_STORAGE_URL must be set in your environment. See Environment Variables.

Usage Patterns

User Avatars (fixed dimensions)

For small, known-size images such as user avatars, always supply explicit width and height values:

import Image from 'next/image';

function Avatar({ url, name }: { url: string; name: string }) {
  return (
    <Image
      src={url}
      width={32}
      height={32}
      alt={`${name}'s avatar`}
      className="rounded-full"
    />
  );
}

Property Photos (fluid / responsive)

For images whose display size is determined by their container (e.g. a photo gallery), use the fill prop inside a relatively-positioned container:

import Image from 'next/image';

function PropertyPhoto({ s3Url, description }: { s3Url: string; description: string }) {
  return (
    <div className="relative w-full" style={{ aspectRatio: '16 / 9' }}>
      <Image
        src={s3Url}
        fill
        alt={description}
        style={{ objectFit: 'cover' }}
        sizes="(max-width: 768px) 100vw, 50vw"
      />
    </div>
  );
}

The sizes prop tells the browser which image variant to download at each breakpoint, reducing unnecessary data transfer on mobile devices.

Checklist for New Image Work

  • Import Image from next/image, not a raw <img> tag.
  • Add the remote hostname to images.remotePatterns in next.config.ts.
  • Provide width + height for fixed-size images, or fill + a positioned container for fluid images.
  • Supply a meaningful alt string on every image.
  • Set the sizes prop on fluid images to optimise bandwidth across breakpoints.
  • Test that the image domain resolves correctly in both development and production environments.

Related