To optimize images for Next.js, let next/image handle resizing and format selection on a server, and shrink the source files yourself so your repo, build and public folder stay light. With output: 'export' there is no server, so you either add a custom loader or ship files that are already small. Pick the row that matches your situation.
| What you have | The problem you hit | The Smol setting |
|---|---|---|
| Photos and heroes in public/ or imported, on a server deployment | Huge sources bloat git and slow builds; next/image already makes the delivered sizes | Compress, original format, quality 85 to 90, maximum dimension about 2x your widest rendered width |
| Static export with unoptimized images | The default loader is unsupported, so the file you commit is the file users download | Compress, output AVIF or WebP, quality 60 to 70, maximum dimension at your rendered width |
| PNG screenshots and illustrations | Large lossless files in git and in the page | Compress, PNG to WebP or AVIF, quality 65 as a starting point |
| A repo already heavy with images | Files over 50 MiB draw a GitHub warning; over 100 MiB are rejected | Batch compress the folder, then commit the copies |
Is next/image enough to optimize images for Next.js?
Often yes. On a server deployment next/image serves correctly sized images, picks a format from the browser’s Accept header (see the Image component reference), lazy loads, and prevents layout shift, per the Next.js images guide. If that is your setup, you do not need another tool in the delivery path. Agencies running many client sites can also see Smol for web agencies.
What it does not do is shrink your repository. It reads the full file you committed and produces smaller variants at request time. A 14 MB source stays 14 MB in git, in every clone and in every CI checkout. This page is about that gap: the source files, and the cases where next/image is switched off. For the page-speed side, see image SEO and page speed.
How do images work with next/image in a static export?
With output: 'export', image optimization using the default loader is not supported. The static export guide lists it under unsupported features, and says to define a custom image loader instead, for example one that builds Cloudinary URLs. The other documented route is the unoptimized prop, which per the Image component reference serves the source “as-is” with no change to quality, size or format.
That second route is where Smol fits. With unoptimized, the bytes you commit are the bytes your visitors download, so the file must already be the right size, quality and format. Compress it to AVIF or WebP at the width you actually render, then point src at it. For the broader loading picture, see image optimization for Core Web Vitals, measured.
| Option | What changes | Where Smol fits |
|---|---|---|
| Custom loader (next.config.js images.loader) | A service resizes per request; you pay or host it | Trim the originals you upload to it |
| unoptimized prop or config | Files are served exactly as committed | Produce the final AVIF, WebP or JPG with Smol |
| Plain <img> or CSS background | No component, no srcset; you control everything | Same: Smol output is the shipped file |
One limit to say out loud: Smol produces one size per run. It does not generate a set of responsive widths from one image, and the default output name is the same for every run (name_compressed.ext). If you need 640, 1200 and 1920 pixel versions for an srcset, that is three runs with renaming, or a build script. For one well-chosen size per image, a single run is enough.
Should I use AVIF in Next.js, and how?
Yes for most photographs, with a fallback. The Next.js docs say AVIF “generally takes 50% longer to encode but it compresses 20% smaller compared to WebP”, and that when you enable both formats, AVIF is preferred for browsers that support it with WebP as the fallback. To enable it on a server deployment, set images.formats to ['image/avif', 'image/webp']. The default is WebP only. Read the The same Image component reference notes that each format is cached separately, which raises storage needs.
For a static export, AVIF means committing the AVIF file. Smol’s own measurements on the benchmark page show the size of the opportunity on 24 small (768 × 512) test photos: AVIF needed 22 to 26% fewer bytes than the best JPEG at the same SSIMULACRA2 score, and compressing those photos from PNG to AVIF at quality 65 saved 92.1%. Camera-size files and illustrations will differ, so judge each by eye. Two honest caveats: the test set is small film photographs, and a browser that cannot decode AVIF needs a fallback in your markup, such as a <picture> element. The AVIF converter page covers the format itself.
How do I keep public folder images and my repo small?
Compress before you commit, because git keeps every version forever. Files in public are served from the site root, and statically imported images get width, height and a blurDataURL automatically, per the images guide. Neither feature shrinks the file. GitHub warns above 50 MiB, rejects above 100 MiB per file, and suggests repositories stay ideally under 1 GB.
Hosts have their own ceilings. Cloudflare Pages allows 25 MiB per asset and 20,000 files per site on the Free plan, which matters when an export copies everything in public. A folder of originals straight from a designer can break a deploy long before it breaks a page.
Once a large file is committed, compressing it later does not remove it from history. Our guide to compressing images before you commit explains why, and that is the reason to make Smol the step between the designer’s export and git add.
Which Smol settings should I use for Next.js images?
Choose by who does the final optimization. Smol’s defaults are quality 75, metadata stripped, and images resized to fit inside 2000 × 2000 pixels unless you change it. Quality numbers below are starting points to check by eye, not guarantees.
| Asset | Output format | Quality (starting point) | Maximum dimension |
|---|---|---|---|
| Hero or full-bleed photo, optimizer runs | Original format | 85 to 90 | About 2x the widest rendered width |
| Hero or full-bleed photo, shipped as-is | AVIF (WebP fallback) | 60 to 70 | The widest rendered width |
| Card, thumbnail or avatar | WebP or AVIF | 65 to 75 | Rendered size, or 2x for high-density screens |
| PNG screenshot | WebP or AVIF | 65 | Rendered width |
| Open Graph or social image | JPG | 75 | Whatever the platform asks for |
Quality belongs to the Compress operation, not Convert, so choose the output format inside a compress job. Resize modes are fit (stays inside the box), fill (covers the box and crops, with no control over what is cropped), and width or height. For layout-safe output, use fit or width. Smol keeps the original when a compression would make the file larger, and by default writes a copy next to it.
What is the workflow from design export to commit?
Find the widest rendered width
Check the largest size the image displays at in your layout, in CSS pixels. Double it only if you serve high-density screens.
Drag the folder into Smol
Whole folders and mixed types are fine. Set the output format and quality from the table above.
Set the maximum dimension
Use the width from step 1 in fit mode. Leave the 2000 px default only if your layout needs it.
Check the result by eye
Open the copies beside the originals at the size users see. Raise quality if gradients band or text fringes.
Replace the sources and commit
Move the
_compressedcopies intopublicor your assets folder, drop the suffix, and commit. The originals stay wherever you keep them.
Save the settings as a preset so the next export is one drag. Presets live on that Mac, so a team agrees the numbers in the README and recreates the preset on each machine.
What do React and Next.js developers use today?
Free and built-in options come first because they are often enough.
| Tool | Good for | Limit |
|---|---|---|
| next/image default loader | Automatic sizes, formats and lazy loading on a server | Unsupported in a static export; does not shrink the repo |
| Custom loader plus a service | Static exports that still want on-demand resizing | An external service in the delivery path |
| sips (built into macOS) | Quick resizes in a shell loop | Very fast, but few controls |
| ImageOptim | Lossless trimming of JPEG and PNG | Gentle by default; smaller gains unless lossy mode is on |
| A build script in CI | Automatic variants on every build | You write and maintain it |
| Smol | Folders of sources to AVIF, WebP or JPG on your Mac, with a quality setting | Manual step; one size per run; macOS only |
For a fuller look at one-off methods, see every Mac compression method compared, and image optimization for web developers. If you need compression on a server instead, the Smol API exists for that.
When is Smol the wrong tool for Next.js images?
- You need responsive sets or on-demand variants. Smol makes one size per run. A loader, a service or a build script generates widths automatically.
- Your pipeline runs on Linux CI. Smol is a Mac app. Use an image library in the build for automation.
- You need pixel-identical output. Smol has no lossless mode and always re-encodes. ImageOptim’s lossless setting is the answer there.
- Your images are SVG. Smol does not handle SVG, and
next/imageserves SVG without optimization anyway. - The project is small and next/image already covers it. If every source is under a few hundred KB, skip the extra step.
Speed note
Smol is not the fastest option: 24 small images take about 7 seconds, where a sips loop takes under one. It is a quality-first step you run before commit, not a hot path.
Frequently asked questions
How do I optimize images for Next.js?
Use next/image for delivery, which serves sized, lazy-loaded images in WebP by default, and shrink the source files before you commit them. Resize to about the widest width you render, then set quality. In a static export, compress to AVIF or WebP yourself, because the default loader is unsupported and unoptimized images ship as committed.
Does next/image work with a static export?
Not with the default loader. The Next.js static export guide lists default-loader image optimization as unsupported and says to define a custom loader in next.config.js, such as one for Cloudinary. The other route is the unoptimized prop, which serves the source file as-is, so the file you commit must already be small.
How do I enable AVIF in Next.js?
Set images.formats to ['image/avif', 'image/webp'] in next.config.js on a server deployment. The docs note AVIF generally takes 50% longer to encode but compresses 20% smaller than WebP, and that each format is cached separately. In a static export, commit AVIF files yourself and keep a fallback for browsers that cannot decode them.
How do I reduce the image size of my repo?
Compress before you commit, since git keeps every version. GitHub warns above 50 MiB per file and rejects above 100 MiB, and suggests repositories stay ideally under 1 GB. Batch compress your images folder in Smol, replace the originals with the smaller copies, and commit. Later compression does not remove old versions from history.
Should public folder images be compressed?
Yes, whenever they are served as-is. Files in public are delivered from the site root without changes, so their size is what users download. If next/image processes them, compress lightly (quality 85 to 90) so the optimizer still has detail. If they ship unoptimized, pick the final format and quality yourself and check the result.
Can Smol generate srcset sizes for Next.js?
No. Smol produces one size per run, and the default output name repeats, so several widths of one image need separate runs and renaming. For automatic responsive sets, use next/image with a server or custom loader, or a build script. Smol suits one well-chosen size per image and shrinking sources before git.
Keep reading
Smol for other teams
