Sveltekit loads images faster

When working on a SvelteKit project, it's common to drop images into the static/
directory and call it a day. It works, it’s simple, and it feels intuitive. But what if I told you that moving your images to src/lib/images
could actually give you a noticeable performance boost?
Let’s explore why that’s the case — and why it might be time to rethink how your app handles images.
static/
Isn’t Always IdealThe static/
folder is essentially a passthrough to the final build. Files here are served as-is and retain their original filenames. This is perfectly fine for assets that need fixed URLs, like robots.txt
or favicons.
But here’s the catch: since these files don’t get any transformation during the build process, they also don’t get cache-busting hashes added to their filenames.
This leads to a problem: when a browser caches an image from static/
, it has no way of knowing when the image changes unless it revalidates with the server. This means every time the browser loads your site, it has to send a request just to check if the image has changed. That might not sound like a big deal — but multiply that by 20 or 30 images on a page, and you’re suddenly looking at significant extra round-trips.
src/lib/images
AdvantageSvelteKit (via Vite) allows you to import images from anywhere inside the src/
directory. When you import an image from src/lib/images
or similar, Vite processes it during the build:
hero.jpg
might become hero.a8d3c1f1.jpg
. This approach dramatically reduces unnecessary revalidation requests and improves loading speed, especially on mobile networks.
src/lib
Here’s how you’d typically import and use an image:
<script>
import hero from '$lib/images/hero.jpg';
</script>
<img src={hero} alt="Hero image" />
This guarantees the image is optimized, hashed, and cache-friendly out of the box.
svelte-preprocess-import-assets
Manually importing every image can get tedious. That’s where the svelte-preprocess-import-assets
plugin comes in. It allows you to reference image paths as if they were in static/
, while still benefiting from Vite’s asset handling.
Instead of:
<script>
import logo from '$lib/images/logo.png';
</script>
<img src={logo} alt="Logo" />
You can write:
<img src="$lib/images/logo.png" alt="Logo" />
The plugin will handle the import behind the scenes during preprocessing. It’s a small quality-of-life improvement, but it adds up over time.
svelte-preprocess-import-assets
npm install --save-dev svelte-preprocess-import-assets
import { importAssets } from 'svelte-preprocess-import-assets';
svelte({ preprocess: [importAssets()] });
// or in svelte.config.js
export default {
preprocess: [importAssets()],
// ... other Svelte options
};
static/
There are still valid use cases for the static/
directory:
/robots.txt
, /manifest.json
, etc.)