Fonts and Images
Astro 6 introduced a Fonts API and has built-in image optimization. Both replace Next.js-specific features.
Fonts API (Astro 6)
The Fonts API downloads fonts at build time and serves them from your own domain. No client-side requests to Google Fonts or other providers.
Setup
// astro.config.mjs
import { defineConfig, fontProviders } from 'astro/config';
export default defineConfig({
fonts: {
providers: [fontProviders.google()],
families: [
{
name: 'Inter',
provider: 'google',
weights: [400, 500, 600, 700],
styles: ['normal', 'italic'],
},
{
name: 'JetBrains Mono',
provider: 'google',
weights: [400, 700],
},
],
},
});
Usage in CSS
The Fonts API generates CSS custom properties:
body {
font-family: var(--font-inter), sans-serif;
}
code {
font-family: var(--font-jetbrains-mono), monospace;
}
Comparison with next/font
| Feature | next/font/google | Astro Fonts API |
|---|---|---|
| Self-hosting | Yes | Yes |
| Build-time download | Yes | Yes |
| CSS variable | Manual setup | Auto-generated --font-* |
| Configuration | Per-file import | Central config |
| No CLS | Yes | Yes |
The Astro approach is simpler: configure once in astro.config.mjs, use CSS variables everywhere.
Images
The <Image /> component
Astro optimizes images at build time via astro:assets:
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
<Image src={heroImage} alt="Hero" width={800} height={400} />
This:
- Converts to WebP/AVIF
- Generates proper
width/heightattributes (no layout shift) - Lazy loads by default
Local images
Import images in the frontmatter:
---
import { Image } from 'astro:assets';
import photo from '../assets/photo.jpg';
---
<Image src={photo} alt="A photo" />
Remote images
Configure allowed domains in astro.config.mjs:
export default defineConfig({
image: {
domains: ['cdn.example.com', 'images.unsplash.com'],
// Or use patterns for more flexibility:
remotePatterns: [
{ protocol: 'https', hostname: '**.example.com' },
],
},
});
Then use remote URLs:
---
import { Image } from 'astro:assets';
---
<Image
src="https://cdn.example.com/photo.jpg"
alt="Remote photo"
width={600}
height={400}
/>
The <Picture /> component
For art direction with multiple formats/sizes:
---
import { Picture } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<Picture
src={hero}
formats={['avif', 'webp']}
alt="Hero image"
widths={[400, 800, 1200]}
sizes="(max-width: 800px) 100vw, 800px"
/>
Images in content collections
Reference images from collection schemas:
// content.config.ts
const blog = defineCollection({
type: 'content',
schema: ({ image }) => z.object({
title: z.string(),
cover: image(),
}),
});
---
title: My Post
cover: ./cover.jpg
---
The image is validated at build time and available for optimization.
Public directory images
Images in public/ are not processed:
<img src="/logo.svg" alt="Logo" />
Use this for SVGs, favicons, and assets that do not need optimization.
Comparison with next/image
| Feature | next/image | Astro <Image /> |
|---|---|---|
| Build-time optimization | No (runtime) | Yes |
| Runtime optimization | Yes (on-demand) | Only with SSR adapter |
| Lazy loading | Default | Default |
| Formats | WebP | WebP, AVIF |
| Layout shift prevention | Yes | Yes |
| Remote images | next.config.js domains | astro.config.mjs domains |
| Import required | next/image | astro:assets |
Key difference: Astro optimizes at build time by default, which means no runtime image processing cost. Next.js optimizes on-demand, which is more flexible but adds server load.