MENU
images Configurations
You can configure the Image Component in next.config.js. The following options are available:
1. localPatterns
Use localPatterns in your next.config.js file to allow images from specific local paths to be optimized and block all others.
module.exports = {
images: {
localPatterns: [
{
pathname: '/assets/images/**',
search: '',
},
],
},
}
The example above will ensure the src property of next/image must start with /assets/images/ and must not have a query string. Attempting to optimize any other path will respond with 400 Bad Request error.
2. remotePatterns
Use remotePatterns in your next.config.js file to allow images from specific external paths and block all others. This ensures that only external images from your account can be served.
module.exports = {
images: {
remotePatterns: [new URL('https://example.com/account123/**')],
},
}
If using a version prior to 15.3.0, you can configure remotePatterns using the object:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
port: '',
pathname: '/account123/**',
search: '',
},
],
},
}
The example above will ensure the src property of next/image must start with https://example.com/account123/ and must not have a query string. Any other protocol, hostname, port, or unmatched path will respond with 400 Bad Request.
Wildcard Patterns: Wildcard patterns can be used for both pathname and hostname and have the following syntax:
- * matches a single path segment or subdomain
- ** matches any number of path segments at the end or subdomains at the beginning. This syntax does not work in the middle of the pattern.
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
port: '',
search: '',
},
],
},
}
This allows subdomains like image.example.com. Query strings and custom ports are still blocked.
Good to know: When omitting protocol, port, pathname, or search then the wildcard ** is implied. This is not recommended because it may allow malicious actors to optimize URLs you did not intend.
Query Strings: You can also restrict query strings using the search property:
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'assets.example.com',
search: '?v=1727111025337',
},
],
},
}
The example above will ensure the src property of next/image must start with https://assets.example.com and must have the exact query string ?v=1727111025337. Any other protocol or query string will respond with 400 Bad Request.
3. loaderFile
loaderFile allows you to use a custom image optimization service instead of Next.js.
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
}
The path must be relative to the project root. The file must export a default function that returns a URL string:
'use client'
export default function myImageLoader({ src, width, quality }) {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
4. deviceSizes
deviceSizes allows you to specify a list of device width breakpoints. These widths are used when the next/image component uses sizes prop to ensure the correct image is served for the user's device.
If no configuration is provided, the default below is used:
module.exports = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
}
5. imageSizes
imageSizes allows you to specify a list of image widths. These widths are concatenated with the array of device sizes to form the full array of sizes used to generate image srcset.
If no configuration is provided, the default below is used:
module.exports = {
images: {
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
}
imageSizes is only used for images which provide a sizes prop, which indicates that the image is less than the full width of the screen. Therefore, the sizes in imageSizes should all be smaller than the smallest size in deviceSizes.
6. qualities
qualities allows you to specify a list of image quality values.
module.exports = {
images: {
qualities: [25, 50, 75],
},
}
In the example above, only three qualities are allowed: 25, 50, and 75. If the quality prop does not match a value in this array, the image will fail with a 400 Bad Request.
7. formats
formats allows you to specify a list of image formats to be used.
module.exports = {
images: {
// Default
formats: ['image/webp'],
},
}
Next.js automatically detects the browser's supported image formats via the request's Accept header in order to determine the best output format.
If the Accept header matches more than one of the configured formats, the first match in the array is used. Therefore, the array order matters. If there is no match (or the source image is animated), it will use the original image's format.
You can enable AVIF support, which will fallback to the original format of the src image if the browser does not support AVIF:
module.exports = {
images: {
formats: ['image/avif'],
},
}
Good to know:
- We still recommend using WebP for most use cases.
- AVIF generally takes 50% longer to encode but it compresses 20% smaller compared to WebP. This means that the first time an image is requested, it will typically be slower, but subsequent requests that are cached will be faster.
- If you self-host with a Proxy/CDN in front of Next.js, you must configure the Proxy to forward the Accept header.
8. minimumCacheTTL
minimumCacheTTL allows you to configure the Time to Live (TTL) in seconds for cached optimized images. In many cases, it's better to use a Static Image Import which will automatically hash the file contents and cache the image forever with a Cache-Control header of immutable.
If no configuration is provided, the default below is used.
module.exports = {
images: {
minimumCacheTTL: 60, // 1 minute
},
}
You can increase the TTL to reduce the number of revalidations and potentially lower cost:
module.exports = {
images: {
minimumCacheTTL: 2678400, // 31 days
},
}
The expiration (or rather Max Age) of the optimized image is defined by either the minimumCacheTTL or the upstream image Cache-Control header, whichever is larger.
If you need to change the caching behavior per image, you can configure headers to set the Cache-Control header on the upstream image (e.g. /some-asset.jpg, not /_next/image itself).
There is no mechanism to invalidate the cache at this time, so it is best to keep minimumCacheTTL low. Otherwise you may need to manually change the src prop or delete the cached file <distDir>/cache/images.
9. disableStaticImages
disableStaticImages allows you to disable static image imports.
The default behavior allows you to import static files such as import icon from './icon.png' and then pass that to the src property. In some cases, you may wish to disable this feature if it conflicts with other plugins that expect the import to behave differently.
You can disable static image imports inside your next.config.js:
module.exports = {
images: {
disableStaticImages: true,
},
}
10. dangerouslyAllowSVG
dangerouslyAllowSVG allows you to serve SVG images.
module.exports = {
images: {
dangerouslyAllowSVG: true,
},
}
By default, Next.js does not optimize SVG images for a few reasons:
- SVG is a vector format meaning it can be resized losslessly.
- SVG has many of the same features as HTML/CSS, which can lead to vulnerabilities without proper Content Security Policy (CSP) headers.
We recommend using the unoptimized prop when the src prop is known to be SVG. This happens automatically when src ends with ".svg".
<Image src="/my-image.svg" unoptimized />
In addition, it is strongly recommended to also set contentDispositionType to force the browser to download the image, as well as contentSecurityPolicy to prevent scripts embedded in the image from executing.
module.exports = {
images: {
dangerouslyAllowSVG: true,
contentDispositionType: 'attachment',
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
}
11. contentDispositionType
contentDispositionType allows you to configure the Content-Disposition header.
module.exports = {
images: {
contentDispositionType: 'inline',
},
}
By default, the loader sets the Content-Disposition header to attachment for added protection since the API can serve arbitrary remote images.
The default value is attachment which forces the browser to download the image when visiting directly. This is particularly important when dangerouslyAllowSVG is true.
You can optionally configure inline to allow the browser to render the image when visiting directly, without downloading it.
The images configuration option in next.config.js allows you to customize how Next.js handles loading.
If you prefer to use a cloud provider to optimize images instead of Next.js's built-in Image Optimization API, you can configure a custom image loader by setting the loader and loaderFile options.
// next.config.js
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
}
The loaderFile path is relative to the root of your Next.js project. This file must export a default function that returns the URL string for the image source with optional width and quality parameters, for example:
// my/image/loader.js
'use client'
export default function myImageLoader({ src, width, quality }) {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}
Alternatively, you can pass a custom loader function via the loader prop directly on each next/image component instance.
Good to know: Customizing the image loader requires using Client Components to serialize the provided function properly.
Example Loaders for Popular Providers
Below are some example custom loaders adapted for various cloud image providers. Replace https://example.com with your actual CDN or image service base URL.
1. Akamai 2256
export default function akamaiLoader({ src, width, quality }) {
return `https://example.com/${src}?imwidth=${width}`
}
2. AWS CloudFront 27
export default function cloudfrontLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('format', 'auto')
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
3. Cloudinary 944
export default function cloudinaryLoader({ src, width, quality }) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://example.com/${params.join(',')}${src}`
}
4. Cloudflare 10
export default function cloudflareLoader({ src, width, quality }) {
const params = [`width=${width}`, `quality=${quality || 75}`, 'format=auto']
return `https://example.com/cdn-cgi/image/${params.join(',')}/${src}`
}
5. Contentful 5571
export default function contentfulLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('fm', 'webp')
url.searchParams.set('w', width.toString())
url.searchParams.set('q', (quality || 75).toString())
return url.href
}
6. Fastly 8594
export default function fastlyLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('auto', 'webp')
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
7. Gumlet 89785
export default function gumletLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('format', 'auto')
url.searchParams.set('w', width.toString())
url.searchParams.set('q', (quality || 75).toString())
return url.href
}
8. ImageEngine
export default function imageengineLoader({ src, width, quality }) {
const compression = 100 - (quality || 50)
const params = [`w_${width}`, `cmpr_${compression}`]
return `https://example.com${src}?imgeng=/${params.join('/')}`
}
9. Imgix 2810
export default function imgixLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
const params = url.searchParams
params.set('auto', params.getAll('auto').join(',') || 'format')
params.set('fit', params.get('fit') || 'max')
params.set('w', params.get('w') || width.toString())
params.set('q', (quality || 50).toString())
return url.href
}
10. PixelBin 74424
export default function pixelBinLoader({ src, width, quality }) {
const name = '<your-cloud-name>'
const opt = `t.resize(w:${width})~t.compress(q:${quality || 75})`
return `https://cdn.pixelbin.io/v2/${name}/${opt}/${src}?f_auto=true`
}
11. Sanity 4962
export default function sanityLoader({ src, width, quality }) {
const prj = 'zp7mbokg'
const dataset = 'production'
const url = new URL(`https://cdn.sanity.io/images/${prj}/${dataset}${src}`)
url.searchParams.set('auto', 'format')
url.searchParams.set('fit', 'max')
url.searchParams.set('w', width.toString())
if (quality) {
url.searchParams.set('q', quality.toString())
}
return url.href
}
12. Sirv 21056
export default function sirvLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
const params = url.searchParams
params.set('format', params.getAll('format').join(',') || 'optimal')
params.set('w', params.get('w') || width.toString())
params.set('q', (quality || 85).toString())
return url.href
}
13. Supabase 25095
export default function supabaseLoader({ src, width, quality }) {
const url = new URL(`https://example.com${src}`)
url.searchParams.set('width', width.toString())
url.searchParams.set('quality', (quality || 75).toString())
return url.href
}
14. Thumbor 955
export default function thumborLoader({ src, width, quality }) {
const params = [`${width}x0`, `filters:quality(${quality || 75})`]
return `https://example.com${params.join('/')}${src}`
}
15. ImageKit.io 11464
export default function imageKitLoader({ src, width, quality }) {
const params = [`w-${width}`, `q-${quality || 80}`]
return `https://ik.imagekit.io/your_imagekit_id/${src}?tr=${params.join(',')}`
}
16. Nitrogen AIO 197136
export default function aioLoader({ src, width, quality }) {
const url = new URL(src, window.location.href)
const params = url.searchParams
const aioParams = params.getAll('aio')
aioParams.push(`w-${width}`)
if (quality) {
aioParams.push(`q-${quality.toString()}`)
}
params.set('aio', aioParams.join(';'))
return url.href
}