Introduction to Astro
At StrapiConf, Matt Kane, framework lead at Astro and former contributor to Gatsby and Netlify, delivered an in-depth talk showcasing why Astro is the best modern web framework for content-driven sites.
With over 25 years of experience, Matt walked us through the philosophy, performance benefits, architecture, and most importantly, how Astro integrates with Strapi to deliver an unparalleled developer and content editing experience.
In this tutorial, we will learn why Astro is the best choice for building content-driven websites.
Video Resource
Here is the complete video for this tutorial by Matt Kane at the just concluded Strapi Conf.
What is Astro?
Astro.js is a web meta-framework which is like Next.js, Remix or Nuxt.js.
We won't dwell on the basics of Astro. Our focus in this tutorial is on content.
Learn Astro.js and Strapi tutorials using these resources.
- Astro & Strapi Website Tutorial: Part 1 - Intro to Astro
- Astro & Strapi Website Tutorial: Part 2 - Intro to Strapi
- Astro & Strapi Website Tutorial: Part 3 - Project Build
Astro Core Features
There are many things that make Astro special. They include.
1. Astro is Designed for Content
Astro is a web framework for content-driven sites. You can build brilliant and interactive apps using Astro. Astro is not all-things for all people. Astro is focused on developers building content-driven sites.
2. Astro is Really Fast
There is no faster framework out there, but Astro ensures your content delivery is fast. It does this in the following ways.
- Server First: By default, Astro is server-first. It first generates your pages as static files. If you don't want your pages to be statically generated, you can opt in to server-side rendering (SSR).
- Zero JavaScript: Since JavaScript is what will slow down your site, Astro sends zero JavaScript by default. We will know why and how in a bit.
- Interactivity: If you need interactivity in Astro, you can clearly specify which bit of your app needs interactivity. This means you have the flexibility to keep the site static and sprinkle interactivity to the parts of your app that need interactivity.
3. Astro Supports JavaScript Frameworks
Another cool trick of Astro is that you can use any JavaScript framework in your Astro application such as Next.js, Vue.js, Svelte, etc. and even plain JavaScript and HTML. You can even import more than one depending on what works for you.
4. Developers Love Astro
The main key thing about Astro is that developers love Astro. Here is the recent State of JavaScript survey for meta-frameworks.
According to the survey above, Astro is number 1 in the following:
- #1 Interest: Developers have heard how great Astro is.
- #1 Positivity: Developers have tried it, and they love it.
- #1 Retention: They tried it and they want to keep using it.
Enough of all the talk about how Astro is great. Let's dive into the content!
Defining Content-Driven Sites and Examples
As we mentioned earlier, Astro is the framework for a content-driven site.
So, what is a content-driven site?
What is a Content-Drivent Site?
The answer would be that it covers a lot of things but primarily any site that is mostly about content rather than about interactivity.
In the beginning, all sites were content-driven sites. Over the years, because more apps have come in, there is more interactivity. However, the majority of sites today are content-driven.
Examples of content-driven sites include
- Marketing Sites: They include Porsche, IKEA, Netlify, etc. where their dot com is on Astro.
- Documentations: An example is Cloudflare which moved their entire docs of tens of thousands of pages to Astro.
- E-commerce: There is interactivity in e-commerce sites. There, you have carts, checkouts, and others. But most e-commerce sites are about products, which are content.
- Blogs: NASA now uses Astro for its blog content.
- Portfolios: This is particularly where people try Astro by building a portfolio website.
With all of these, there comes an intuitive question:
"Why do content-driven sites need a new approach? Why should you go for Astro which is specifically for content when you have Frameworks like Next.js that can do everything?"
The answer is that JavaScript is slow and HTML is fast.
Let's learn why in the next section.
Why JavaScript is Slow and HTML is Fast
Content-driven sites need a different approach because JavaScript is slow and HTML is fast. Thus, we have Astro which is specifically for content.
Relatively, JavaScript is slow. It makes your site slower than it needs to be by rendering content to the Document Object Model (DOM). So, JavaScript will slow down your page when you are setting up content-driven sites with lots of pages.
Instead of JavaScript, how about HTML? If you have a very massive number of pages, it will still be super fast because it is just HTML and not JavaScript.
But then, why should we care about speed? JavaScript is slow and HTML is fast, why does speed matter?
Why Does Speed Matter?
Even though JavaScript will slow down your site by a few hundred milliseconds, does it matter?
According to Deloitte, "Milliseconds make millions" in a study on how improvements in mobile site speed positively affect a brands bottom line.
Here is why speed matters according to the survey by Delloite:
- Retail: 8.4% increase in conversions
- Travel: 10.1% increase in conversions
- Luxury: 8% increase in conversions
- Lead generation information page bounce rate improved by 8.3%
These are big numbers that translate to millions and billions of Dollars and Euros.
But, how is Astro Fast?
How is Astro Fast?- Astro Islands Architecture
Astro is fast by having less JavaScript through its Islands Architecture or Astro Islands. Astro’s secret is its islands architecture.
Islands architecture is when Astro renders the majority of your page as static HTML with smaller “islands” of JavaScript added for interactivity or personalization such as an image carousel, for example.
The image below is a typical e-commerce page with lots of content, interactivity, personalizations, and so on. Now, how do islands come into play?
NOTE: In the image above, the parts highlighted in red need interactivity. The parts highlighted in green change all the time.
Here is what we have in the image above:
- Most of the stuff on this page is relatively static, and won’t change very often. It could be statically generated or cached for a long time. There are a few exceptions though.
- The highlighted parts of the page are some of the things that aren’t static. At the top, there’s the user’s profile pic. That’ll need to change on every request.
- On the right there’s the block showing the number of rooms available. Now some unscrupulous sites might fake that one, but we’re all honest here, so let’s say we regenerate this every minute.
- Down at the bottom we have “recommended for you”. We’ll want to generate this uniquely for the user on every page load.
If we want to keep all these updated, we might just server-render the page on every request. This lets us use the user’s cookie and update all the dynamic parts.
However, that’s not the most efficient way though. What if we can cache the static parts, but server-render the dynamic parts? Thus, the bulk of the page will load quickly, but the other parts can still be fresh. This is where server islands come in.
Adding Islands in Astro
You just need to add the client
directive to add islands to the part of your site that needs interactivity.
For example, here is an Astro component below:
1---
2import { SearchBar } from "./components/SearchBar.tsx";
3import {Avatar } from "./components/Avatar.tsx";
4---
5
6<nav>
7 <SearchBar client:load/>
8 <Avatar/>
9</nav>
10<main>
11 <slot/>
12</main>
In the code above:
- We imported 2 React components, SearchBar and Avatar.
- The Avatar component doesn't need to be interactive. The same goes for the rest of the app except the
SearchBar
. - In order to make the SearchBar interactive, which is zero JavaScript, we added
client:load
to the SearchBar component. - With the
client:load
directive that we added to the SearchBar component, when the page loads, it will load the React runtime and just the amount of JavaScript it needs for interactivity. This will happen after the full page is loaded.
That’s all you need to turn it into an island. By default, it will send no JS, but add that directive and load the JavaScript, and make it interactive once the page has loaded.
Apart from client:load
directive, there are others with a distinct use case.
client:visible
: Use this when it is offscreen and you want to scroll it into view.client:only
: Use this when it is fully client-side rendered.
Astro Server Islands
If you take a look at the image above, the parts highlighted green can't be pre-rendered or cached for a long time. This is because they change. They include:
- The avatar: This should change on every page load because you want to see your beautiful face while you are doing a shopping.
- The number of rooms: This can be updated every hour.
- The Recommended Trips: This should also change and should be personalized based on browser history.
So, how do we not server-render the whole page every single time considering that you have some parts that don't need to be server-rendered?
The first guess would be to use a React component that will call an API and all that. But that means you will use more JavaScript.
One thing you can do in Astro to solve this is to use the server:defer
. This way you tell Astro what part you want to server-render and the part you want as static.
1---
2import { SearchBar } from "./components/SearchBar.tsx";
3import {Avatar } from "./components/Avatar.tsx";
4---
5
6<nav>
7 <SearchBar client:load/>
8 <Avatar server:defer/>
9</nav>
10<main>
11 <slot/>
12</main>
In the code above, we have server-rendered the Avatar component because they change often.
Managing Content in Astro with Content Collections - with Strapi
As a framework aimed at content-driven sites, Astro gives you a lot of tools for managing content. It is not just about being fast that makes Astro content-driven but comes with a lot of tools for making your content easy to manage.
When you want to start building, the first thing you want to do is to create a lib
folder, a loader, and so on. With Strapi client API and other ways of fetching content, the most important thing to consider is to get your content loaded.
Astro has a unified way of loading content. Let's learn how Astro does it.
Managing Content in Astro with Content Collections
One of Astro's strongest features for content-driven development is its built-in Content Collections system.
Let's walk through how developers can load, validate, and use content with ease.
What Are Content Collections in Astro?
Astro’s content collections allow developers to organize Markdown or other file-based content using folders and define content models via Zod schemas. This provides a structured, fully typed, and validated way to manage local content.
For example, a blog can be constructed using Markdown files stored in a src/content/blog/
directory. Each Markdown file includes metadata like title
, description
, createdAt
, updatedAt
, and heroImage
Here is our content configuration file:
1// Path: ./src/content.config.ts
2
3import { defineCollection, z } from "astro:content";
4import { glob } from "astro/loaders";
5
6const blog = defineCollection({
7 loader: glob({ base: "./src/content/blog", pattern: "**/*.md" }),
8 schema: z.object({
9 title: z.string(),
10 description: z.string().optional(),
11 createdAt: z.coerce.date(),
12 updatedAt: z.coerce.date().optional(),
13 heroImage: z.string().optional(),
14 }),
15});
16
17export const collection = { blog };
In the code above we did the following:
- Used the built-in Astro glob loader, which is for loading files from disk, to load a folder filled with markdown files.
- Added a schema for the metadata of the Blog content using Zod by validating the metadata and some transformations.
Now that you have defined the Blog collection above, you can proceed to use this wherever you want to use it inside any of your components.
Loading and Displaying Content with Astro
Using getCollection()
function, developers can fetch and display content anywhere in their Astro site. The content is strongly typed and easily rendered with JSX or Astro components.
1// Path: ./src/pages/blog/[slug].astro
2
3---
4import { type CollectionEntry, getCollection } from "astro::content";
5import BlogPost from "../../Layouts/BlogPost.astro";
6import { render } from "astro::content";
7
8export async function getStaticProps() {
9 const blog = await getCollection("blog");
10
11 return blog.map((post) => ({
12 params: { slug: post.id },
13 props: post,
14 }));
15}
16
17const post = Astro.props;
18const { Content } = await render(post);
19---
20
21<BlogPost {...post.data}>
22 <Content />
23</BlogPost>;
In the code above, the getCollection
gets the blog
collection and inserts it into the parameter for the blog page.
Why Markdown Alone Isn’t Enough
Markdown is a great starting point for content, but it's limited. As content needs scale and editorial teams grow a full CMS becomes necessary.
“Editing markdown files in code is not a great experience for content editors.”
This is where Strapi a flexible and scalable content management solution is needed.
Integrating Strapi with Astro for CMS-Driven Content
Astro’s content loader API makes it seamless to integrate external data sources like Strapi.
Recall that in our code above, we have the Blog collection which is loaded by the glob
loader. In Astro, you can also create or write a loader by yourself. Or, you can distribute loaders as plugins.
The strapi-community-astro-loader, is a community-developed plugin by Paul from Strapi. With this loader, let's load a Page collection.
See the code below:
1// Path: ./src/content.config.ts
2
3// ... other imports
4
5import { strapiLoader } from "strapi-community-astro-loader";
6
7// ... initial Blog Collection
8
9const pages = defineCollection({
10 loader: strapiLoader({
11 contentType: "page",
12 params: {
13 populate: {
14 blocks: populateBlocks,
15 },
16 },
17 }),
18});
19
20export const collection = { blog, pages };
We used the Strapi loader to load the contents of the Pages collection from Strapi.
To use this, we are also going to call the getCollection()
function as we did when pulling the markdown as shown below:
1...
2
3const blog = await getCollection("blog");
4const pages = await getCollection("blog");
The getCollection()
function ensures the following:
- Unified loading patterns.
- Strong typing (TypeScript support auto-generated from the Strapi schema).
- Fewer code changes when switching from static to dynamic content.
The same developer experience you had with Markdown now works seamlessly with Strapi.
Conclusion
Astro doesn’t just make your website faster, it makes your entire team more productive. Astro's server-first philosophy, zero-JavaScript by default approach, and islands architecture make it the ideal choice for teams who care deeply about performance, simplicity, and developer experience.
As content teams scale and need to evolve beyond markdown files, integrating a powerful headless CMS becomes essential. That’s where Strapi shines.
If you’re building content-driven sites, whether for blogs, documentation, portfolios, or e-commerce Astro and Strapi are what you need.
See Strapi in action with an interactive demo
Theodore is a Technical Writer and a full-stack software developer. He loves writing technical articles, building solutions, and sharing his expertise.