Documentation Index Fetch the complete documentation index at: https://mintlify.com/withastro/astro/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Astro is designed for performance by default with zero JavaScript shipped to the client unless you explicitly add it. This guide covers techniques to further optimize your site for maximum speed.
Image Optimization
Images are often the largest assets on a webpage. Astro provides built-in image optimization through the <Image> component.
Using the Image Component
src/components/Hero.astro
---
import { Image } from 'astro:assets' ;
import heroImage from '../assets/hero.jpg' ;
---
< Image
src = { heroImage }
alt = "Hero image"
width = { 1200 }
height = { 600 }
loading = "eager"
format = "webp"
/>
Benefits of Image Optimization
Automatic Resizing Images are resized to specified dimensions, reducing file size.
Format Conversion Convert to modern formats like WebP and AVIF automatically.
Lazy Loading Images load only when they enter the viewport.
Responsive Images Serve appropriately sized images based on device and screen size.
Remote Images
Optimize images from external sources:
---
import { Image } from 'astro:assets' ;
---
< Image
src = "https://example.com/photo.jpg"
alt = "Remote image"
width = { 800 }
height = { 600 }
inferSize
/>
Content Collections with Images
import { defineCollection , z } from 'astro:content' ;
import { glob } from 'astro/loaders' ;
const blog = defineCollection ({
loader: glob ({ base: './src/content/blog' , pattern: '**/*.md' }),
schema : ({ image }) => z . object ({
title: z . string (),
heroImage: image (),
}),
});
export const collections = { blog };
src/layouts/BlogPost.astro
---
import { Image } from 'astro:assets' ;
const { heroImage , title } = Astro . props ;
---
< article >
< Image
src = { heroImage }
alt = { title }
width = { 1020 }
height = { 510 }
format = "webp"
/>
</ article >
Prefetching
Prefetch pages before users navigate to them for instant page transitions.
Enabling Prefetch
Configure prefetch in astro.config.mjs
import { defineConfig } from 'astro/config' ;
export default defineConfig ({
prefetch: {
prefetchAll: true ,
defaultStrategy: 'hover' ,
} ,
}) ;
Add data attributes to links
< nav >
< a href = "/about" data-astro-prefetch > About </ a >
< a href = "/blog" data-astro-prefetch = "hover" > Blog </ a >
< a href = "/contact" data-astro-prefetch = "tap" > Contact </ a >
</ nav >
Prefetch Strategies
Prefetch when the user hovers over a link (default): < a href = "/about" data-astro-prefetch = "hover" > About </ a >
Best for: Desktop navigation where hover intent is clear.
Prefetch when the user taps/clicks a link: < a href = "/products" data-astro-prefetch = "tap" > Products </ a >
Best for: Mobile devices or slow connections.
Prefetch when links enter the viewport: < a href = "/blog/post" data-astro-prefetch = "viewport" > Read More </ a >
Best for: Lists of links where users are likely to click visible items.
Prefetch immediately when the page loads: < a href = "/checkout" data-astro-prefetch = "load" > Checkout </ a >
Best for: Critical next steps in user flows.
Programmatic Prefetching
---
// Server-side
---
< script >
import { prefetch } from 'astro:prefetch' ;
// Prefetch on custom event
document . querySelector ( '#important-link' )
. addEventListener ( 'focus' , () => {
prefetch ( '/important-page' );
});
// Prefetch multiple pages
const pages = [ '/about' , '/contact' , '/pricing' ];
pages . forEach ( page => prefetch ( page ));
</ script >
Code Splitting
Astro automatically code-splits your JavaScript to load only what’s needed.
Client Directives
Control when JavaScript loads for interactive components:
---
import Counter from '../components/Counter.jsx' ;
import Chat from '../components/Chat.svelte' ;
import Analytics from '../components/Analytics.vue' ;
---
<!-- Load immediately -->
< Counter client:load />
<!-- Load when component is visible -->
< Chat client:visible />
<!-- Load when page is idle -->
< Analytics client:idle />
<!-- Only hydrate on media query match -->
< MobileMenu client:media = "(max-width: 768px)" />
Directive Priority
client:load
Highest priority. Load and hydrate immediately on page load.
Use for: Critical interactive elements above the fold.
client:idle
Load once the page is done with initial load and the requestIdleCallback event has fired.
Use for: Non-critical widgets and chat boxes.
client:visible
Load once the component enters the user’s viewport.
Use for: Below-the-fold interactive content.
client:media
Load only when a media query matches.
Use for: Mobile-only or desktop-only components.
client:only
Skip server-side rendering entirely. Hydrate only on client.
Use for: Components that rely heavily on browser APIs.
Asset Optimization
CSS Optimization
Astro automatically:
Scopes CSS to prevent conflicts
Minifies CSS in production
Removes unused CSS
Bundles CSS efficiently
src/components/Card.astro
< div class = "card" >
< slot />
</ div >
< style >
.card {
/* This CSS is automatically scoped and optimized */
border-radius : 0.5 rem ;
padding : 1 rem ;
}
</ style >
Font Optimization
Optimize web font loading:
src/components/BaseHead.astro
< head >
<!-- Preload critical fonts -->
< link
rel = "preload"
href = "/fonts/inter-var.woff2"
as = "font"
type = "font/woff2"
crossorigin
/>
</ head >
< style is:global >
@font-face {
font-family : 'Inter' ;
src : url ( '/fonts/inter-var.woff2' ) format ( 'woff2' );
font-weight : 100 900 ;
font-display : swap ; /* Show fallback while loading */
}
</ style >
Script Optimization
Optimize third-party scripts:
<!-- Defer non-critical scripts -->
< script defer src = "/analytics.js" ></ script >
<!-- Load scripts only when needed -->
< script >
// Load Google Maps only when user clicks
document . querySelector ( '#map-trigger' ). addEventListener ( 'click' , () => {
const script = document . createElement ( 'script' );
script . src = 'https://maps.googleapis.com/maps/api/js' ;
document . head . appendChild ( script );
});
</ script >
Build Optimization
Minimize Bundle Size
Remove Unused Dependencies
Audit your dependencies regularly: Remove packages you’re not using: npm uninstall unused-package
Import heavy libraries only when needed: ---
// Don't import at the top if not always needed
// import { Chart } from 'heavy-chart-library';
---
< button id = "load-chart" > Load Chart </ button >
< script >
document . querySelector ( '#load-chart' ). addEventListener ( 'click' , async () => {
// Import only when needed
const { Chart } = await import ( 'heavy-chart-library' );
new Chart ( /* ... */ );
});
</ script >
Configure Vite to optimize specific dependencies: import { defineConfig } from 'astro/config' ;
export default defineConfig ({
vite: {
optimizeDeps: {
include: [ 'heavy-library' ],
},
} ,
}) ;
Caching Strategies
Static Asset Caching
Configure your hosting provider to cache static assets:
Cache-Control: public, max-age=31536000, immutable
For Netlify:
[[ headers ]]
for = "/_astro/*"
[ headers . values ]
Cache-Control = "public, max-age=31536000, immutable"
For Vercel:
{
"headers" : [
{
"source" : "/_astro/(.*)" ,
"headers" : [
{
"key" : "Cache-Control" ,
"value" : "public, max-age=31536000, immutable"
}
]
}
]
}
Lighthouse Scores
Run Lighthouse audits regularly:
npm install -g lighthouse
lighthouse https://your-site.com --view
Core Web Vitals
Monitor key metrics:
LCP Largest Contentful Paint Target: < 2.5s Optimize images and fonts.
FID First Input Delay Target: < 100ms Minimize JavaScript.
CLS Cumulative Layout Shift Target: < 0.1 Reserve space for images.
Best Practices Checklist
Use the Image component
Always use <Image> for local and remote images to get automatic optimization.
Enable prefetching
Configure prefetch for smoother navigation between pages.
Choose appropriate client directives
Use client:idle or client:visible for non-critical components.
Optimize fonts
Preload critical fonts and use font-display: swap.
Lazy load below-the-fold content
Use loading="lazy" for images and client:visible for components.
Minimize third-party scripts
Defer or dynamically load analytics and other third-party code.
Monitor performance
Regularly check Lighthouse scores and Core Web Vitals.
Advanced Optimizations
Deploy to edge networks for faster response times: import { defineConfig } from 'astro/config' ;
import cloudflare from '@astrojs/cloudflare' ;
export default defineConfig ({
output: 'server' ,
adapter: cloudflare () ,
}) ;
Edge rendering reduces latency by serving content from locations close to users.
Only hydrate the interactive parts of your page: ---
// Most of the page is static HTML
---
< header >
< h1 > My Site </ h1 >
</ header >
< main >
< p > This content is static and fast. </ p >
<!-- Only this button needs JavaScript -->
< InteractiveButton client:visible />
</ main >
Implement offline support and advanced caching: self . addEventListener ( 'install' , ( event ) => {
event . waitUntil (
caches . open ( 'v1' ). then (( cache ) => {
return cache . addAll ([
'/' ,
'/styles.css' ,
'/script.js' ,
]);
})
);
});
self . addEventListener ( 'fetch' , ( event ) => {
event . respondWith (
caches . match ( event . request ). then (( response ) => {
return response || fetch ( event . request );
})
);
});