We use cookies to enhance your experience on the site
CodeWorlds
Back to collections
Guide12 min read

Astro 6, a content framework built on island architecture

Astro ships zero JavaScript by default and adds interactivity through islands. Version 6, Fonts API, Live Content Collections, SSR, and a Next.js comparison.

Astro 6, a content framework built on island architecture

Astro renders pages to plain HTML and ships no JavaScript to the browser by default. Interactive parts are added deliberately, as islands, each with its own moment of hydration. Version 6.0 arrived on 10 March 2026 with a built in fonts API, a content security policy API, and content collections that refresh without rebuilding the site.

Where the zero JavaScript comes from

A classic SPA framework sends the browser all the code needed to construct the interface, even when the page is an article where nothing is clickable. Astro inverts that: an .astro component runs at build time or on the server, and what reaches the client is the result, namely HTML.

An island is the exception to that rule. You mark a React, Vue, or Svelte component with a directive, and Astro ships a JavaScript bundle for it and boots it according to the chosen strategy. The rest of the page stays static, so you pay for interactivity only where you asked for it.

The effect shows in metrics. A content site built with Astro usually loads tens of kilobytes instead of hundreds, and Largest Contentful Paint drops below a second on an average connection. For sites whose traffic comes from search, that translates directly into rankings, since Core Web Vitals feed into page assessment.

What changed in version 6

Astro 6.0 landed in March 2026, release 6.4 at the end of May. The changes worth knowing when planning an upgrade:

The Fonts API self hosts and optimises typefaces with no configuration. The usual manual routine disappears: downloading files, generating character subsets, declaring @font-face, adding preload hints. For languages with diacritics, the saving is visible in transfer size.

The Content Security Policy API lets you describe your policy in configuration rather than bolting headers onto the hosting layer. Framework injected scripts get correct hashes automatically, which used to be the reason teams gave up on CSP.

Live Content Collections refresh content at request time without rebuilding the whole site. That answers the most common complaint about static generators: a typo in an article required a full build.

The dev server was rewritten on Vite's Environment API, so development runs the same runtime as production. Differences between local dev and a deployment on Cloudflare Workers, Bun, or Deno become rarer as a result. In version 6 the Rust compiler sat behind an experimental.rustCompiler flag, alongside the default compiler written in Go.

Version 6 is no longer the current line. Astro 7.0 shipped on 22 June 2026 and closes the compiler thread: the Rust based @astrojs/compiler-rs replaced its Go predecessor and runs without a flag, Markdown and MDX processing moved to native code as well, and the bundler is Vite 8 with Rolldown. The maintainers report build times cut by 15 to 61 percent on their own benchmarks. Seven is also stricter about invalid HTML: an unclosed tag raises an error instead of being silently corrected. The @astrojs/db package is gone too, along with the astro db, astro login, and astro link commands. The islands, collections, and adapters described below behave identically in both lines, so this holds for a project on seven as well.

Installation and project structure

Code
Bash
npm create astro@latest my-site
cd my-site
npm run dev

The project has four directories worth knowing: src/pages defines routes from filenames, src/components holds components, src/content carries Markdown or MDX content, and public serves assets untouched.

An .astro component consists of a script section between triple dashes and a template below it.

Code
ASTRO
---
const posts = Object.values(import.meta.glob('../content/blog/*.md', { eager: true }))
const latest = posts.slice(0, 5)
---

<ul>
  {latest.map((post) => (
    <li><a href={post.url}>{post.frontmatter.title}</a></li>
  ))}
</ul>

Code in the upper section runs on the server or at build time and never reaches the browser. You can query a database, read a file, or call an API there without exposing keys.

Islands and client directives

The directive decides when an island receives JavaScript. Choosing between them affects metrics more than image optimisation does.

DirectiveWhen it runsTypical use
client:loadImmediately after the page loadsCart, theme switch above the fold
client:idleOnce the browser goes quietSecondary widgets that can wait a moment
client:visibleWhen the element enters the viewportGallery, map, comments at the bottom
client:mediaWhen a media query matchesMobile menu that desktop never needs
client:onlyClient side only, no server HTMLComponent that depends on window
Code
ASTRO
---
import Gallery from '../components/Gallery.jsx'
import MobileMenu from '../components/MobileMenu.vue'
---

<Gallery client:visible photos={photos} />
<MobileMenu client:media="(max-width: 768px)" />

The default choice should be client:visible. If the component happens to be visible right away it behaves like client:load, and if it sits further down, its code will not block first render.

Keep in mind too that an island receives data only through props, and only props that serialise. A function passed from the script section into a client component will not survive the boundary, and a large object passed wholesale inflates the HTML, since Astro has to embed it in the document for the island to boot. Pass the minimum and fetch the rest inside the component.

Astro lets you mix frameworks on one page, though that is rarely a good idea in a product a team maintains. Two libraries mean two runtime bundles and two sets of conventions. The reasonable exceptions are a migration or a single third party component.

Content Collections

Collections give typed access to content. A schema describes the frontmatter and Astro validates it at build time, so a typo in a field name stops the build instead of breaking a page in production.

TSsrc/content.config.ts
TypeScript
// src/content.config.ts
import { defineCollection, z } from 'astro:content'
import { glob } from 'astro/loaders'

const blog = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
  schema: z.object({
    title: z.string().max(60),
    description: z.string().min(120).max(160),
    publishedAt: z.date(),
    tags: z.array(z.string()).default([])
  })
})

export const collections = { blog }

Schemas are written in Zod, so enforcing title and description lengths against search engine limits takes two lines. It is a simple way to impose SEO discipline while writing rather than during an audit after launch.

The glob loader reads files from disk, but a collection can just as well pull from a CMS or a database. Version 6 adds a variant refreshed at request time, which lets you keep articles in Sanity or Contentful without rebuilding the site after every correction.

Static, server rendered, or in between

Astro builds statically until you say otherwise. Server rendering is enabled by an adapter and an output setting, and the decision can be made per page.

astro.config.mjs
JavaScript
// astro.config.mjs
import { defineConfig } from 'astro/config'
import vercel from '@astrojs/vercel'

export default defineConfig({
  output: 'server',
  adapter: vercel()
})
Code
ASTRO
---
export const prerender = true
---

That line in a specific page returns it to static generation despite the global server mode. The reverse, prerender = false, works under static output.

Server islands are a separate mechanism: the page reaches the browser as static HTML while user specific fragments arrive through a later request. A product page can then be served entirely from cache and still show a current stock count.

Adapters exist for Vercel, Netlify, Cloudflare, Node, Deno, and Bun. Switching platforms usually changes one configuration line, which sets Astro apart from frameworks bound more tightly to a single vendor.

Astro against Next.js and the rest

FrameworkStrengthWeaknessPick it when
AstroLeast JavaScript, any UI framework insidePoor fit for state driven applicationsBlog, documentation, company site, SEO focused store
Next.jsMature ecosystem, Server Components, full stackMore client code on simple pagesApp with authentication, dashboards, heavy interactivity
NuxtVue ergonomics, good conventionsTies you to the Vue ecosystemThe team works in Vue
SvelteKitSmall output bundles, simple reactivity modelSmaller communityBundle size is the critical constraint

The split is less sharp than comparisons suggest. Astro will serve an admin panel, and Next.js will build a blog. The real question is which dominates: content read by people and crawlers, or application state changing in response to clicks.

Performance and SEO in practice

The framework alone does not settle results. Three things make the biggest difference in projects I have seen.

Images through the <Image /> component rather than a raw <img>. Astro generates modern formats and writes dimensions, which removes the layout shift on load that Cumulative Layout Shift penalises.

Fonts through the built in API instead of a link to an external provider. That drops one network connection and one moment when text is invisible.

Third party scripts, meaning analytics, chat widgets, and marketing pixels, loaded on interaction or with a delay. It happens that a project with zero JavaScript of its own ships 300 kilobytes of vendor code, because marketing keeps adding tools. Astro has no say in that, so agree on a budget and check it during audits.

Metadata generated from collections rather than typed into every page. A single SEO component reading frontmatter fields guarantees that each article carries a title, description, canonical URL, and structured data. Missing fields then surface at build time, because the schema demands them.

Deployment and running costs

A fully static site uploads to any file host, including the free tiers of GitHub Pages, Cloudflare Pages, and Netlify. The bill starts growing only under server mode, since every request then invokes a function.

OptionWhat you pay forWhen it pays off
Static on a free plan0 USD, with transfer and build minute limitsBlog, documentation, company site up to a few hundred pages
Static with CDN on a paid planfrom roughly 20 USD per monthHigh traffic site needing sub 100 ms response times
Server mode with functionsinvocations plus execution timePersonalisation, cart, content behind a login
Static with server islandsfunction cost for fragments onlyCached page with a few dynamic elements

The last row is usually the best compromise for a store or a content site. The page is served from cache and costs pennies, while functions run only for the fragment showing a price or stock level.

The second line item is build minutes. A site with five thousand pages can take well over ten minutes to build, and rebuilding fully after every content correction burns through a free allowance quickly. This is where request time collections earn their place, since they confine full builds to code changes.

When migrating an existing site, plan the redirects. Astro handles them in configuration, which beats a rules file at the hosting layer, because they land in the repository alongside the code.

Code
JavaScript
export default defineConfig({
  redirects: {
    '/blog/[slug]': '/articles/[slug]',
    '/old-offer': { status: 301, destination: '/offer' }
  }
})

Check your URL list in Search Console before and after the switch. Ranking losses during a technology change come, in most cases, not from the framework but from abandoned URLs that suddenly return 404.

Common mistakes

The first is client:load everywhere. At that point Astro stops differing from a classic application, only with an extra compilation layer.

The second is reaching for global state across islands. Islands are separate component trees and share neither React context nor a Vue store. Keep shared state in a framework agnostic library or in URL parameters.

The third is holding content outside collections. Files read manually through glob carry no validation and no types, so a frontmatter mistake shows up on the page instead.

The fourth is skipping prerender under server mode. Pages that could be fully static get generated on every request, and you pay for it in response time and function bills.

FAQ

Is Astro suitable for applications, not just sites?

It is suitable, though not built for it. A dashboard full of forms and state dependent views is more comfortable in Next.js or SvelteKit. Astro wins where most views are content and interactivity comes in islands.

Can I use React in Astro?

Yes, after adding the integration, React components run as islands. The limitation is that each island is a separate tree: context, providers, and global stores do not cross between them.

What does migrating from Next.js look like?

Routes move file by file, since both map a directory onto URLs. The data fetching layer takes the most work, because getStaticProps and Server Components have no literal equivalent and their role passes to code in the component script section. Starting with the content section and leaving the dashboard for later is the sensible order.

Does Astro support TypeScript?

Yes, support is built in and needs no configuration. Content collections generate types from schemas, so frontmatter fields autocomplete in the editor and a misspelled name stops the build.

Does version 6 require rewriting a version 5 project?

Not in the typical case. The changes mostly touch internals: the dev server and the build pipeline. Before upgrading, check community integrations, since those most often need a new release.

The release announcement sits on the Astro blog, and the full documentation at docs.astro.build.