---
title: "21 — Production Optimization — Images, Fonts, Scripts, Metadata, and Observability"
uid: production-optimization
tags: ["observability", "roadmap:nextjs", "fonts", "web-vitals", "optimization", "metadata", "images", "nextjs"]
excerpt: "The production checklist isn't 'build it yourself' — it's use what's already here: next/image, next/font, next/script, the Metadata API, instrumentation."
date: 2026-08-13T03:27:58+0000
source: https://www.aveshina.my.id/en/blog/production-optimization
---

Everything that mattered before shipping turned out to be already installed. The model that clicked: **Next.js ships built-in components and APIs that handle the optimizations that matter — next/image for images, next/font for fonts, next/script for third-party scripts, the Metadata API for SEO, and instrumentation hooks for observability** [1][2][3][4][5]. The production checklist isn't "build it all yourself" — it's "use what's already here."

## Images — the biggest page-weight lever

Images account for a huge portion of typical page weight and have a sizable impact on LCP (how fast the largest visible element loads) [2]. The next/image component extends the HTML <img> with automatic optimization:

- **Size optimization** — serves correctly sized images per device, in modern formats (WebP, AVIF).
- **Visual stability** — prevents layout shift while loading.
- **Faster page loads** — lazy-loads images as they enter the viewport, with optional blur-up placeholders.
- **Asset flexibility** — on-demand resizing, even for remote images.

```
import Image from 'next/image';

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

The priority prop on above-the-fold images is the one to remember — it tells the browser to load that image eagerly, which matters for LCP.

## Fonts — self-hosted, no layout shift

The next/font module automatically optimizes fonts and removes external network requests, with built-in self-hosting for any font file [3]. The result: optimally loaded web fonts with no layout shift. No more FOIT/FOUT (text flashing invisible or unstyled before the font arrives), no requests to third-party font CDNs, no cumulative layout shift from late-arriving fonts.

```
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });

export default function RootLayout({ children }) {
  return <html className={inter.className}>…</html>;
}
```

## Scripts — controlled loading

Third-party scripts (analytics, ads, social widgets) often require downloading and executing code from external servers, which can hurt performance [4]. The next/script component optimizes when and how scripts execute — afterInteractive, lazyOnceVisible, etc. — so a third-party script doesn't block the first paint.

## Metadata — SEO and shareability

The Metadata APIs define the app's metadata for SEO and web shareability [5]. Three forms:

- A static metadata object exported from a layout or page.
- A dynamic generateMetadata function for per-request metadata.
- Special file conventions for favicons and OG images (static or dynamically generated).

```
// app/page.tsx
export const metadata = {
  title: 'Ave — Portfolio',
  openGraph: { images: ['/og.png'] },
};
```

## Package bundling and lazy loading

By default, packages imported into Server Components and Route Handlers are automatically bundled for optimization [6]. For the client side, **lazy loading** defers Client Components and imported libraries so they're included in the bundle only when needed [7]. A modal that opens on click doesn't need to ship in the initial bundle.

```
import dynamic from 'next/dynamic';
const HeavyChart = dynamic(() => import('./HeavyChart'));
```

## Static assets and third parties

Static files live in the public/ folder, referenced from the base URL [8]. Note that Next.js can't safely cache public assets because they may change. For popular third-party libraries (Google Analytics, Tag Manager), @next/third-parties provides optimized integrations [9].

## Observability — analytics and instrumentation

Production means measuring. Next.js has built-in support for performance metrics via useReportWebVitals, or Vercel's managed analytics service [10]. **Instrumentation** integrates monitoring and logging tools so I can track performance and behavior and debug production issues [11]. For vendor-agnostic observability, Next.js recommends **OpenTelemetry** — a platform-agnostic instrumentation standard supported out of the box [12].

```figure
<svg viewBox="0 0 720 320" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Production optimization areas as a checklist. Six boxes: next/image (sized, modern formats, lazy), next/font (self-hosted, no layout shift), next/script (deferred execution), Metadata API (SEO + OG), lazy loading + bundling (smaller client JS), and observability (web vitals + OpenTelemetry).">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <rect x="40" y="40" width="200" height="90" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="140" y="62" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">next/image</text>
    <text x="140" y="80" font-size="10" fill="#475569" text-anchor="middle">right size per device</text>
    <text x="140" y="96" font-size="10" fill="#475569" text-anchor="middle">WebP / AVIF</text>
    <text x="140" y="112" font-size="10" fill="#475569" text-anchor="middle">lazy + priority</text>

    <rect x="260" y="40" width="200" height="90" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="360" y="62" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">next/font</text>
    <text x="360" y="80" font-size="10" fill="#475569" text-anchor="middle">self-hosted</text>
    <text x="360" y="96" font-size="10" fill="#475569" text-anchor="middle">no external request</text>
    <text x="360" y="112" font-size="10" fill="#475569" text-anchor="middle">no layout shift</text>

    <rect x="480" y="40" width="200" height="90" rx="8" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="580" y="62" font-size="12" font-weight="700" fill="#422006" text-anchor="middle">next/script</text>
    <text x="580" y="80" font-size="10" fill="#475569" text-anchor="middle">controlled load timing</text>
    <text x="580" y="96" font-size="10" fill="#475569" text-anchor="middle">afterInteractive</text>
    <text x="580" y="112" font-size="10" fill="#475569" text-anchor="middle">lazyOnceVisible</text>

    <rect x="40" y="160" width="200" height="90" rx="8" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="140" y="182" font-size="12" font-weight="700" fill="#500724" text-anchor="middle">Metadata API</text>
    <text x="140" y="200" font-size="10" fill="#475569" text-anchor="middle">title, description</text>
    <text x="140" y="216" font-size="10" fill="#475569" text-anchor="middle">OG images</text>
    <text x="140" y="232" font-size="10" fill="#475569" text-anchor="middle">generateMetadata</text>

    <rect x="260" y="160" width="200" height="90" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="360" y="182" font-size="12" font-weight="700" fill="#052e16" text-anchor="middle">Lazy load + bundle</text>
    <text x="360" y="200" font-size="10" fill="#475569" text-anchor="middle">dynamic imports</text>
    <text x="360" y="216" font-size="10" fill="#475569" text-anchor="middle">auto-bundled server pkgs</text>
    <text x="360" y="232" font-size="10" fill="#475569" text-anchor="middle">smaller client JS</text>

    <rect x="480" y="160" width="200" height="90" rx="8" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="580" y="182" font-size="12" font-weight="700" fill="#1e1b4b" text-anchor="middle">Observability</text>
    <text x="580" y="200" font-size="10" fill="#475569" text-anchor="middle">useReportWebVitals</text>
    <text x="580" y="216" font-size="10" fill="#475569" text-anchor="middle">instrumentation hook</text>
    <text x="580" y="232" font-size="10" fill="#475569" text-anchor="middle">OpenTelemetry</text>

    <text x="360" y="296" font-size="11" font-style="italic" fill="#64748b" text-anchor="middle">built-in components and APIs — use them, don't roll your own</text>
  </g>
</svg>
```

## Memory usage

As apps grow, they demand more resources when building locally or creating production builds [13]. Next.js documents strategies for optimizing memory and addressing common memory issues — worth consulting when builds start hitting limits.

## How I use this

Before shipping, I run through the built-in optimizations: every image goes through next/image (with priority on the LCP image), fonts through next/font, third-party scripts through next/script, and metadata defined via the Metadata API on every route. Heavy client components get lazy-loaded. On the observability side, I wire up web-vitals reporting and (for larger apps) OpenTelemetry instrumentation so production behavior is measurable. The discipline is to trust the framework's components — they're tuned for the cases that matter, and rolling my own rarely beats them.

## References

[1] Vercel, "How to optimize your Next.js application for production," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/production-checklist](https://nextjs.org/docs/app/guides/production-checklist)

[2] Vercel, "Image optimization," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/getting-started/images](https://nextjs.org/docs/app/getting-started/images)

[3] Vercel, "Font optimization," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/getting-started/fonts](https://nextjs.org/docs/app/getting-started/fonts)

[4] Vercel, "How to load and optimize scripts," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/scripts](https://nextjs.org/docs/app/guides/scripts)

[5] Vercel, "Metadata and OG images," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/getting-started/metadata-and-og-images#static-open-graph-images](https://nextjs.org/docs/app/getting-started/metadata-and-og-images#static-open-graph-images)

[6] Vercel, "How to optimize package bundling," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/package-bundling](https://nextjs.org/docs/app/guides/package-bundling)

[7] Vercel, "How to lazy load Client Components and libraries," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/lazy-loading](https://nextjs.org/docs/app/guides/lazy-loading)

[8] Vercel, "public folder," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/api-reference/file-conventions/public-folder](https://nextjs.org/docs/app/api-reference/file-conventions/public-folder)

[9] Vercel, "How to optimize third-party libraries," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/third-party-libraries](https://nextjs.org/docs/app/guides/third-party-libraries)

[10] Vercel, "How to add analytics to your Next.js application," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/analytics](https://nextjs.org/docs/app/guides/analytics)

[11] Vercel, "How to set up instrumentation," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/instrumentation](https://nextjs.org/docs/app/guides/instrumentation)

[12] Vercel, "How to set up instrumentation with OpenTelemetry," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/open-telemetry](https://nextjs.org/docs/app/guides/open-telemetry)

[13] Vercel, "How to optimize memory usage," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/app/guides/memory-usage](https://nextjs.org/docs/app/guides/memory-usage)

```quiz
Q: What does the next/image component automatically handle?
- Image compression only
- Right-sized images per device, modern formats (WebP/AVIF), lazy loading, and layout-shift prevention
correct: 1
explain: next/image extends <img> with automatic size optimization, modern format serving, lazy loading via the viewport, and visual stability. The priority prop marks above-the-fold images for eager loading.

Q: Why does next/font remove layout shift?
- It inlines fonts as base64
- It self-hosts the font and preloads it, removing external network requests and the late-arriving font that causes shift
correct: 1
explain: next/font self-hosts and preloads fonts, eliminating the third-party request and the late-arriving, unstyled text that causes layout shift.

Q: What's the difference between a static metadata object and generateMetadata?
- Nothing — they're aliases
- The static object is the same for every request; generateMetadata is a function that returns per-request metadata
correct: 1
explain: export a static metadata object for page-wide constants; export a generateMetadata function when metadata depends on request data (params, cookies).

Q: What's the purpose of lazy loading via next/dynamic?
- To cache components server-side
- To defer loading Client Components and libraries so they ship only when needed, shrinking the initial bundle
correct: 1
explain: dynamic imports split a component into its own chunk loaded on demand. A modal opened on click doesn't bloat the initial bundle.

Q: For vendor-agnostic production observability, Next.js recommends…
- a custom logging endpoint
- OpenTelemetry, supported out of the box
correct: 1
explain: OpenTelemetry is a platform-agnostic instrumentation standard. Next.js instruments itself with OTel out of the box, letting you swap providers without changing code.
```
