Images + fonts cheatsheet.

next/image basics

import Image from "next/image";

<Image src="/photo.jpg" width={400} height={300} alt="..." />

Generates AVIF/WebP, srcSet, lazy-loads by default.

Local imports (auto-sized)

import photo from "@/public/photo.jpg";

<Image src={photo} alt="..." placeholder="blur" />

Type and dimensions inferred. placeholder="blur" generates a base64 LQIP.

Remote images

<Image src="https://cdn.example.com/x.jpg" width={400} height={300} alt="..." />

Configure allowed hosts in next.config.js:

module.exports = {
  images: {
    remotePatterns: [
      { protocol: "https", hostname: "cdn.example.com" },
      { protocol: "https", hostname: "**.example.com" },
    ],
  },
};

priority (LCP image)

<Image src="/hero.jpg" width={1200} height={600} priority alt="..." />

Use for above-the-fold images. Eager loads, preloads.

Fill (responsive)

<div style={{ position: "relative", aspectRatio: "16/9" }}>
  <Image src="/banner.jpg" alt="..." fill style={{ objectFit: "cover" }} />
</div>

Fills the parent. Parent must be positioned.

sizes attribute

<Image
  src="/x.jpg"
  width={1200}
  height={800}
  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 800px"
  alt="..."
/>

Tells browser which size to download. Critical for responsive images.

blur placeholder

<Image src={photo} alt="..." placeholder="blur" />

// Custom blurDataURL for remote:
<Image
  src="https://..."
  width={400}
  height={300}
  alt="..."
  placeholder="blur"
  blurDataURL="data:image/svg+xml;base64,..."
/>

Quality

<Image src="/x.jpg" width={400} height={300} quality={75} alt="..." />

Default 75. Lower = smaller files.

Loader (custom CDN)

// next.config.js
module.exports = {
  images: {
    loader: "custom",
    loaderFile: "./image-loader.ts",
  },
};
// image-loader.ts
export default function loader({ src, width, quality }) {
  return `https://cdn.example.com/${src}?w=${width}&q=${quality ?? 75}`;
}

Disable optimization (sometimes)

<Image src="/x.svg" width={100} height={100} unoptimized alt="..." />

For SVGs or already-optimized images.

next/font (Google)

// app/layout.tsx
import { Inter } from "next/font/google";

const inter = Inter({
  subsets: ["latin"],
  display: "swap",
  variable: "--font-inter",
});

export default function Layout({ children }) {
  return (
    <html className={inter.variable}>
      <body>{children}</body>
    </html>
  );
}
body { font-family: var(--font-inter); }

Multiple weights / styles

const inter = Inter({
  subsets: ["latin"],
  weight: ["400", "700"],
  style: ["normal", "italic"],
});

Variable fonts (preferred)

const inter = Inter({ subsets: ["latin"] });    // variable, all weights

Smaller bundle, all weights available.

Local fonts

import localFont from "next/font/local";

const myFont = localFont({
  src: [
    { path: "./MyFont-Regular.woff2", weight: "400", style: "normal" },
    { path: "./MyFont-Bold.woff2", weight: "700", style: "normal" },
  ],
  variable: "--font-my",
  display: "swap",
});

Place files in app/fonts/ (or anywhere local).

Multiple fonts

import { Inter, JetBrains_Mono } from "next/font/google";

const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
const mono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-mono" });

<html className={`${inter.variable} ${mono.variable}`}>

Tailwind integration

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ["var(--font-sans)"],
        mono: ["var(--font-mono)"],
      },
    },
  },
};
<body class="font-sans">
  <code class="font-mono">...</code>
</body>

Preload control

const myFont = localFont({
  src: "./X.woff2",
  preload: false,    // don't preload (rarely needed)
});

SVG handling

Next won’t optimize SVGs by default. Two options:

  1. Use <img> directly: <img src="/icon.svg" />
  2. Import as React component with @svgr/webpack:
// next.config.js
module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ["@svgr/webpack"],
    });
    return config;
  },
};

Common mistakes

  • Missing width/height (or fill) → layout shift.
  • No sizes → downloads too-large images on mobile.
  • priority on every image → kills perf.
  • Remote images without remotePatterns → blocked.
  • quality={100} everywhere → huge files.
  • Loading entire Google Fonts CSS instead of using next/font — slow.

Read this next

If you want my image + font setup, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .