Skip to main content
Images can significantly impact your app’s performance. For best results, you should generate optimal formats, create different sizes for different screens, and ensure assets can be cached effectively.

Overview

There are several approaches to image optimization in SvelteKit:

Vite assets

Built-in asset handling with imports

@sveltejs/enhanced-img

Automatic optimization and responsive images

CDN

Dynamic optimization for CMS images

Vite’s built-in handling

Vite automatically processes imported assets for improved performance:
  • Adds hashes to filenames for caching
  • Inlines small assets (below assetsInlineLimit)
  • Works with CSS url() function
  • Handles images, video, audio, and more
<script>
	import logo from '$lib/assets/logo.png';
</script>

<img alt="The project logo" src={logo} />
Vite asset handling is great for basic needs but doesn’t create responsive images or convert formats.

@sveltejs/enhanced-img

The enhanced image plugin provides automatic optimization:
1

Install the package

npm i -D @sveltejs/enhanced-img
2

Configure Vite

vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import { enhancedImages } from '@sveltejs/enhanced-img';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    enhancedImages(), // must come before sveltekit()
    sveltekit()
  ]
});
3

Use enhanced images

<enhanced:img src="./path/to/image.jpg" alt="A description" />

What it does

Automatically generates modern formats like .avif and .webp with fallbacks
Creates multiple sizes and generates srcset attributes for different devices
Sets width and height automatically to prevent layout shift
Strips EXIF data from images

Basic usage

Use <enhanced:img> instead of <img>:
<enhanced:img src="./path/to/your/image.jpg" alt="An alt text" />
At build time, this becomes an <img> wrapped by a <picture> with multiple formats and sizes.
Provide images at 2x resolution for HiDPI displays. The plugin will automatically generate smaller versions for standard displays.

Dynamic image selection

Import images with the ?enhanced query parameter:
<script>
	import MyImage from './path/to/image.jpg?enhanced';
</script>

<enhanced:img src={MyImage} alt="some alt text" />

Responsive images with sizes

For large images, specify sizes to serve smaller versions on smaller devices:
<enhanced:img 
	src="./hero.png" 
	sizes="min(1280px, 100vw)"
/>
Specify exact widths with the w query parameter:
<enhanced:img
  src="./image.png?w=1280;640;400"
  sizes="(min-width:1920px) 1280px, (min-width:1080px) 640px, (min-width:768px) 400px"
/>

Per-image transforms

Apply transforms via query parameters:
<enhanced:img src="./image.jpg?blur=15" alt="Blurred background" />
Available transforms:
  • blur - Gaussian blur radius
  • quality - Compression quality (0-100)
  • flatten - Flatten alpha channel
  • rotate - Rotation angle
  • flip - Flip horizontally
  • flop - Flip vertically
  • And many more

Intrinsic dimensions

width and height are inferred automatically, but you can override them with CSS:
<style>
	.hero-image img {
		width: var(--size);
		height: auto;
	}
</style>

<div class="hero-image">
	<enhanced:img src="./hero.jpg" alt="Hero" />
</div>

Build caching

The first build takes longer due to image processing. Results are cached in ./node_modules/.cache/imagetools for fast subsequent builds.

Loading images from a CDN

For images from a CMS or database, use a CDN with dynamic optimization:

CDN benefits and tradeoffs

  • Images optimized at request time
  • More flexibility with sizes
  • No build-time processing
  • Dynamic image sources (CMS, user uploads)
  • Potential usage costs
  • First request may be slow (lazy generation)
  • Requires proper caching strategy
  • Additional dependency

Example with @unpic/svelte

<script>
	import { Image } from '@unpic/svelte';
</script>

<Image
	src="https://cdn.example.com/image.jpg"
	layout="constrained"
	width={800}
	height={600}
	alt="A cat"
/>

Best practices

1

Choose the right solution

  • Static assets in repo: Use Vite or @sveltejs/enhanced-img
  • CMS images: Use CDN with @unpic/svelte
  • Meta tags: Use Vite’s import handling
2

Provide high-quality sources

Images should be 2x the display size for HiDPI screens. Optimization tools will scale down but can’t add detail.
3

Use sizes attribute

For images larger than ~400px, specify sizes so smaller devices load appropriate versions:
<enhanced:img 
  src="./hero.jpg" 
  sizes="min(1280px, 100vw)"
/>
4

Prioritize important images

For LCP images, set fetchpriority="high" and avoid loading="lazy":
<enhanced:img 
  src="./hero.jpg" 
  fetchpriority="high"
  alt="Hero image"
/>
5

Always provide alt text

The Svelte compiler warns if you omit alt attributes:
<enhanced:img src="./image.jpg" alt="Descriptive text" />
6

Serve via CDN

Use a CDN to reduce latency by distributing assets globally, regardless of your optimization approach.

Common pitfalls

Don’t use em or rem in sizes with modified root font-size:
/* Bad: will cause incorrect image sizing */
html { font-size: 62.5%; }
When used in sizes or @media queries, em and rem use the user’s default font size, not your CSS-modified value.
@sveltejs/enhanced-img only optimizes local files:It can’t optimize images from:
  • Your database
  • A CMS
  • User uploads
  • External URLs
For these cases, use a CDN solution.

Performance metrics

Proper image optimization improves:
LCP (Largest Contentful Paint)
metric
Fast-loading hero images improve LCP scores
CLS (Cumulative Layout Shift)
metric
Setting width and height prevents layout shift
Bandwidth usage
metric
Smaller files and modern formats reduce data transfer

Learn more

Web.dev: Optimize Cumulative Layout Shift