> ## 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.

# Performance Optimization

> Best practices for optimizing Astro site performance including image optimization, prefetching, and build optimization

## 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

```astro title="src/components/Hero.astro" theme={null}
---
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

<CardGroup cols={2}>
  <Card title="Automatic Resizing" icon="image">
    Images are resized to specified dimensions, reducing file size.
  </Card>

  <Card title="Format Conversion" icon="refresh">
    Convert to modern formats like WebP and AVIF automatically.
  </Card>

  <Card title="Lazy Loading" icon="zap">
    Images load only when they enter the viewport.
  </Card>

  <Card title="Responsive Images" icon="layout">
    Serve appropriately sized images based on device and screen size.
  </Card>
</CardGroup>

### Remote Images

Optimize images from external sources:

```astro theme={null}
---
import { Image } from 'astro:assets';
---

<Image
  src="https://example.com/photo.jpg"
  alt="Remote image"
  width={800}
  height={600}
  inferSize
/>
```

### Content Collections with Images

```ts title="src/content.config.ts" theme={null}
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 };
```

```astro title="src/layouts/BlogPost.astro" theme={null}
---
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

<Steps>
  <Step title="Configure prefetch in astro.config.mjs">
    ```js title="astro.config.mjs" theme={null}
    import { defineConfig } from 'astro/config';

    export default defineConfig({
      prefetch: {
        prefetchAll: true,
        defaultStrategy: 'hover',
      },
    });
    ```
  </Step>

  <Step title="Add data attributes to links">
    ```astro theme={null}
    <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>
    ```
  </Step>
</Steps>

### Prefetch Strategies

<Accordion title="Hover Strategy">
  Prefetch when the user hovers over a link (default):

  ```astro theme={null}
  <a href="/about" data-astro-prefetch="hover">About</a>
  ```

  Best for: Desktop navigation where hover intent is clear.
</Accordion>

<Accordion title="Tap Strategy">
  Prefetch when the user taps/clicks a link:

  ```astro theme={null}
  <a href="/products" data-astro-prefetch="tap">Products</a>
  ```

  Best for: Mobile devices or slow connections.
</Accordion>

<Accordion title="Viewport Strategy">
  Prefetch when links enter the viewport:

  ```astro theme={null}
  <a href="/blog/post" data-astro-prefetch="viewport">Read More</a>
  ```

  Best for: Lists of links where users are likely to click visible items.
</Accordion>

<Accordion title="Load Strategy">
  Prefetch immediately when the page loads:

  ```astro theme={null}
  <a href="/checkout" data-astro-prefetch="load">Checkout</a>
  ```

  Best for: Critical next steps in user flows.
</Accordion>

### Programmatic Prefetching

```astro theme={null}
---
// 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:

```astro theme={null}
---
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

<Steps>
  <Step title="client:load">
    Highest priority. Load and hydrate immediately on page load.
    Use for: Critical interactive elements above the fold.
  </Step>

  <Step title="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.
  </Step>

  <Step title="client:visible">
    Load once the component enters the user's viewport.
    Use for: Below-the-fold interactive content.
  </Step>

  <Step title="client:media">
    Load only when a media query matches.
    Use for: Mobile-only or desktop-only components.
  </Step>

  <Step title="client:only">
    Skip server-side rendering entirely. Hydrate only on client.
    Use for: Components that rely heavily on browser APIs.
  </Step>
</Steps>

## Asset Optimization

### CSS Optimization

Astro automatically:

* Scopes CSS to prevent conflicts
* Minifies CSS in production
* Removes unused CSS
* Bundles CSS efficiently

```astro title="src/components/Card.astro" theme={null}
<div class="card">
  <slot />
</div>

<style>
  .card {
    /* This CSS is automatically scoped and optimized */
    border-radius: 0.5rem;
    padding: 1rem;
  }
</style>
```

### Font Optimization

Optimize web font loading:

```astro title="src/components/BaseHead.astro" theme={null}
<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:

```astro theme={null}
<!-- 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

<Accordion title="Remove Unused Dependencies">
  Audit your dependencies regularly:

  ```bash theme={null}
  npx depcheck
  ```

  Remove packages you're not using:

  ```bash theme={null}
  npm uninstall unused-package
  ```
</Accordion>

<Accordion title="Use Dynamic Imports">
  Import heavy libraries only when needed:

  ```astro theme={null}
  ---
  // 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>
  ```
</Accordion>

<Accordion title="Optimize Dependencies">
  Configure Vite to optimize specific dependencies:

  ```js title="astro.config.mjs" theme={null}
  import { defineConfig } from 'astro/config';

  export default defineConfig({
    vite: {
      optimizeDeps: {
        include: ['heavy-library'],
      },
    },
  });
  ```
</Accordion>

## Caching Strategies

### Static Asset Caching

Configure your hosting provider to cache static assets:

```
Cache-Control: public, max-age=31536000, immutable
```

For Netlify:

```toml title="netlify.toml" theme={null}
[[headers]]
  for = "/_astro/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"
```

For Vercel:

```json title="vercel.json" theme={null}
{
  "headers": [
    {
      "source": "/_astro/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=31536000, immutable"
        }
      ]
    }
  ]
}
```

## Performance Monitoring

### Lighthouse Scores

Run Lighthouse audits regularly:

```bash theme={null}
npm install -g lighthouse
lighthouse https://your-site.com --view
```

### Core Web Vitals

Monitor key metrics:

<CardGroup cols={3}>
  <Card title="LCP" icon="clock">
    **Largest Contentful Paint**

    Target: \< 2.5s

    Optimize images and fonts.
  </Card>

  <Card title="FID" icon="pointer">
    **First Input Delay**

    Target: \< 100ms

    Minimize JavaScript.
  </Card>

  <Card title="CLS" icon="layout">
    **Cumulative Layout Shift**

    Target: \< 0.1

    Reserve space for images.
  </Card>
</CardGroup>

## Best Practices Checklist

<Steps>
  <Step title="Use the Image component">
    Always use `<Image>` for local and remote images to get automatic optimization.
  </Step>

  <Step title="Enable prefetching">
    Configure prefetch for smoother navigation between pages.
  </Step>

  <Step title="Choose appropriate client directives">
    Use `client:idle` or `client:visible` for non-critical components.
  </Step>

  <Step title="Optimize fonts">
    Preload critical fonts and use `font-display: swap`.
  </Step>

  <Step title="Lazy load below-the-fold content">
    Use `loading="lazy"` for images and `client:visible` for components.
  </Step>

  <Step title="Minimize third-party scripts">
    Defer or dynamically load analytics and other third-party code.
  </Step>

  <Step title="Monitor performance">
    Regularly check Lighthouse scores and Core Web Vitals.
  </Step>
</Steps>

## Advanced Optimizations

<Accordion title="Edge Rendering">
  Deploy to edge networks for faster response times:

  ```js title="astro.config.mjs" theme={null}
  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.
</Accordion>

<Accordion title="Partial Hydration">
  Only hydrate the interactive parts of your page:

  ```astro theme={null}
  ---
  // 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>
  ```
</Accordion>

<Accordion title="Service Workers">
  Implement offline support and advanced caching:

  ```js title="public/sw.js" theme={null}
  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);
      })
    );
  });
  ```
</Accordion>
