This episode covers managing images and assets in Nuxt: optimization with the @nuxt/image module, using the public folder for static assets, responsive images with NuxtImg, lazy loading, and media optimization strategies for performance.

Images are usually the biggest contributor to page size. A store page with unoptimized product photos can be several seconds slower — while users may leave before the images even load. Episode 9 covers how to handle images and assets in Nuxt correctly.
We'll learn to use @nuxt/image for automatic optimization, understand the difference between the public and assets folders, set up responsive images with lazy loading, and build a media strategy that balances quality and speed.
The @nuxt/image module provides the <NuxtImg /> component that optimizes images automatically — format conversion, resizing, and caching. Install and enable it:
npm install @nuxt/imageexport default defineNuxtConfig({
modules: ["@nuxt/image"],
})After that, the <NuxtImg /> component is available across the whole project without imports.
Replace plain <img> tags with <NuxtImg />:
<template>
<NuxtImg
src="/produk/sneakers.jpg"
alt="Sepatu sneakers putih"
width="800"
height="600"
/>
</template><NuxtImg src="/produk/sneakers.jpg" /> produces an image resized to your needs and uses modern formats like WebP when supported. The width and height attributes prevent layout shift while the image loads.
Files in app/public are served as-is at the root URL. Product photos, favicons, and download files should go here:
app/public/
favicon.ico
produk/
sneakers.jpg
jaket.jpgThe file app/public/favicon.ico is accessible as /favicon.ico. The image at app/public/produk/sneakers.jpg is accessed as /produk/sneakers.jpg.
The app/assets folder is for files processed by the build tooling — for example CSS, fonts, or SVG files imported from code. Unlike public, files in assets don't automatically get a URL; you have to import them.
import logo from "~/assets/svg/logo.svg"import logo from "~/assets/svg/logo.svg" includes the file in the bundle and produces a hashed URL. The rule of thumb: use public for files whose names don't change at build time, and assets for files that get processed.
Use the sizes option to serve image sizes matching the device screen:
<NuxtImg
src="/produk/jaket.jpg"
alt="Jaket denim"
sizes="sm:100vw md:50vw lg:400px"
/>NuxtImg sizes="sm:100vw md:50vw lg:400px" tells the browser how wide the image is needed at each breakpoint, so phones don't download the large desktop version.
For images that aren't immediately visible, enable lazy loading:
<NuxtImg
src="/produk/tas.jpg"
alt="Tas kulit"
loading="lazy"
fetchpriority="low"
/>loading="lazy" makes the image load only when it approaches the viewport. The most important above-the-fold images should instead use fetchpriority="high" so they load first.
For the best results, combine several strategies:
The @nuxt/image module supports these remote providers. If all images are optimized, consider using nuxt.config to set the default provider.
Measure the impact of your optimizations by checking performance audits. Run a production build then review the page size:
npm run build
du -sh .output/publicThe du -sh .output/public command gives you an overview of the total size of served static assets. If this folder grows dramatically, there are likely unoptimized images or original files that are too large.
Episode 9 settles your image handling: <NuxtImg /> from @nuxt/image optimizes automatically, the public folder serves static assets while the assets folder processes files at build time, sizes and lazy loading tailor delivery per device, and size audits keep performance under control.
Key takeaways:
@nuxt/image provides the <NuxtImg /> component with built-in optimization.app/public have direct URLs; files in app/assets must be imported.sizes to serve images according to the device viewport.In the next episode, episode 10, we will discuss forms and validation — building client forms with v-model, validation with VeeValidate, server-side form processing with server actions, and form UX covering errors, loading, and accessibility. Your store's checkout will start working.