Updated on September 27, 2024
·Originally published on June 14, 2023
Astro is an open-source web framework. It’s focused on performance and content-heavy websites like landing pages, blogs, technical documentation, and more.
Like Next.js, Sveltekit, Nuxt.js, and SolidStart, Astro has its own single-file components (which leverages the island architecture, more on that in a bit) and handles the build process for you.
This post is a tour of Astro and its features. We’ll use a website for an imaginary conference as the basis of a mini tutorial. And as always, you can find the complete code on GitHub. This is 100% compatible with Astro v3.
Ready? Let’s get started!
Astro describes itself as an “all in one” web framework, with everything you need to create a website — and a suite of extra integrations available should you want to customize your project further. It’s component agnostic, useful for static site generation, and flexible enough to support single-page and multi-page applications.
In its own words, Astro is built around five core design principles which are set out in its documentation, and which might help you decide if it’s the right choice for your project:
Content-driven: Astro is designed around showcasing content, and so is ideal for content-rich websites that need to reach audiences quickly.
Server-first: Astro prioritizes server-rendering over client-side rendering in-browser to help websites run faster.
Fast by default: By pre-rendering to static HTML, Astro achieves speedy load times and enhanced SEO, which can be useful in contexts where engagement and conversions are a priority.
Easy-to-use: Astro aims to be accessible, “regardless of skill level or past experience with web development.” Its UI language is a superset of HTML but it incorporates features from other JavaScript framework languages like JSX, React, Svelte, and Vue.
Developer-focused: An open-source project, Astro has invested in a range of developer tools and boasts of community-supported documentation available in 14 languages.
Astro stands out by offering speed and flexibility in one convenient package — but how does it do that? Let’s take a deeper dive into some of Astro’s most interesting capabilities.
Unlike some other frameworks, Astro is HTML-first, outputs zero JavaScript by default, and supports both static site generation (SSG) and server-side rendering (SSR). Astro uses that nimbleness and speed to support content load times.
Astro components are similar to Svelte: JavaScript, HTML, and CSS are clearly separated. It doesn’t use JSX. For example:
Astro isn't just a glorified static site generator. I like to think of Astro as “the framework of all frameworks,” not in terms of dominance but of compatibility. Astro is unique among the JavaScript frameworks in that it supports other UI frameworks.
That’s right, you can import components written in React, Preact, Svelte, Vue, Lit, or Solid directly into Astro, and even mix them within the same file.
Yes, Astro supports components from multiple frameworks. It’s incredible. And it's all possible with the following command:
npx astro add @astrojs/react @astrojs/svelte @astrojs/vue
And, because Astro outputs zero JavaScript by default, the bundle size does not increase for each new framework. Each component gets server-rendered and turned into static HTML so you won’t have to worry about the interoperability of different languages.
If you want interactivity, you need to add the client:load directive
, and then the framework’s runtime will be loaded client-side. This is an implementation of what’s called “island architecture.”
The idea of island architecture is to build websites that are static HTML-first, and that restrict interactivity (and the JavaScript associated with it) to specific parts. These parts are isolated “islands” and are loaded after the main static site content. In this way, Astro can serve as both a static site generator while offering robust options for interactivity across an entire site.
As we saw earlier, on top of letting you reuse components created in React, Svelte, and other frameworks, Astro has its own component system. Let's dive into how Astro components work.
Here’s what a component for a basic conference talk would look like:
The front matter contains JS that the server will run, before sending the resulting data to the HTML.
Our component expects a name and a time property, which we’re setting up using Astro.props and giving default values ("Learn Astro
" and "2023-09-23T13:30:00
"). Then, we're using those values in our HTML with {}, like in Svelte or other template files. This is just an example.
We can pass values/props from a parent component to a child component, like so:
As with other frameworks, the file structure in your src/pages directory translates into the pages of your website. Here’s an example folder structure for our Astro site:
Our index.astro
file from before will become the index file of our website. Now what’s that about.md
file? We'll see this in the next section but before we do, let's talk about dynamic routing.
In a lot of scenarios, you don't want to be creating single files for every page of your website. Your content might come from the API of a headless CMS or content platform (like, you know, Contentful), or you could be using any kind of dynamic data.
That's called a dynamic route, and Astro supports this using a []
syntax in the filename. Dynamic routing parameters enable Astro to create multiple pages automatically which is always useful if you need a lot of a certain type of page — maybe you need lots of product spec pages, or bios for different authors, or in our conference example, speaker bios. To learn more about dynamic routing, check out the Astro docs.
Remember the directory structure we looked at above? Astro lets you turn Markdown and MDX files directly into pages on your website. All you have to do is specify a layout value in the front matter.
An about page as a Markdown file would look like this:
Now what's that layout property about?
In Astro, (like Svelte and Qwik) you can use a <slot>
element to specify where the children of a component should be inserted.
For example, it's common to have a component that contains your base HTML, the navigation, and the footer.
A layout component is technically just like any other component, but it's made exclusively to contain others.
Astro supports MDX via an integration. MDX is "Markdown for the component era" which allows you to insert components into your Markdown documents.
In the case of Astro, the <Chart />
component above will be an Astro component.
You can enable the MDX by installing the integration using the following command:
npx astro add mdx
There's a lot more you can do with MDX. Again, you can check out the Astro docs to find out more.
Let's continue with a hypothetical Astro project for a conference website.
You've created a Markdown file for each talk. The file looks like this:
Now, scale this to 20 talks. What happens if, in one of the files, you typed "titlr" instead of title? Your build process might break, or someone's talk title might not be shown.
It would be great if the framework could warn you about these things, right? This is where Content Collections in Astro come in.
Content Collections adds types, required properties, and many other features that make working with Markdown files a lot less error-prone.
Let's turn our example into a content collection.
Create a new folder named content in the src directory, like so:
In that folder, add your Markdown files
Now, create a config file in ./src/content/config.js
. (This can be a TypeScript file too.)
Now that our talks are defined as a collection, we need to slightly tweak the code to display them in your app.
Update your component code so it looks like this:
References are a perennial problem with working with Markdown files. To use our conference website as an example, if we have a collection of talks that all have a speaker's name attached to them, our Markdown front matter would look like this:
But what if a speaker is giving two different talks? Or what if you want to have a dedicated speaker page on the website for each speaker with their details? This is the same problem that blogs face with their authors. The answer is either duplicate information (like using the speaker's name twice), or create some kind of ID for the speaker to use in one file, reference it in the other, and code something to make it work.
Astro takes care of this for you in Content Collections.
First let's create a second collection for our speakers, so that our config file looks like this:
Create at least one Markdown file for a speaker in ./src/content/speaker
.
Then, add a reference to your talk
collection in your config file.
Now, if you forget to add a speaker to your talk's markdown, Astro will tell you and show you a (helpful!) error message:
Content Collections also let you use Markdoc, which is kind of like MDX.
Markdoc is another Astro integration that lets you add Astro components to your Markdown using a shortcode syntax.
Custom components are wrapped in tags that look like this: {% tags %}
.
This is what a Highlight
component in Markdoc would look like:
First, our conference website was a bunch of scattered Markdown files. Next, we gave it structure using Content Collections. Then we added complexity by catering for the case "What if you need references?"
Now, let's add another layer of complexity. What if you need a dynamic page that relies on an API? What if you want to show the current weather forecast at the conference? You can't rebuild your whole site every time the forecast changes, right? (Especially if you live in Northern Europe).
Enter: Hybrid Rendering.
With Hybrid Rendering, you can specify which of your routes should be static and which should be dynamically rendered on the server.
You enable Hybrid Rendering by adding output: "hybrid"
, to your global Astro config file ./astro.config.mjs
, where all your integrations are. (Not to be confused with the ./content/config.js
file that we created earlier).
In production, you'll have to use an SSR adapter, which could be Vercel, Deno, or anything else the Astro team is kind enough to provide for us.
Once it's enabled, everything should continue to work as normal, because static site rendering is the default.
Let's create a new "venue" page for our conference and request some dynamic data for it.
Now, let's call an API to get the sunrise and sunset times at our hypothetical venue. This a basic and contrived example, but it's just to give you an idea of what you can do with this technology.
Here's the final file.
We’ve seen some of the most interesting things that Astro can bring to a website build, and how to achieve them. It’s clear that the framework is more than just a static site generator, so if you do opt for Astro JS, what benefits can you expect for your project — and your entire site — once it’s up and running?
SEO value: Since it is static HTML-first, Astro’s pages are easier for search engines to digest than JS-heavy counterparts, and so typically rank higher thanks to their increased organic profile.
Democratized development: If you can write in HTML, you can develop your website with Astro. The framework also supports TypeScript, features a versatile CLI, and can be augmented with a range of plugins and integrations, so you can layer in complexity as and when you need it. Since it’s an open source language, you could push Astro even further to meet customization requirements.
Feature depth: Astro developers can access a depth of extra features out of the box, including capabilities to display content in multiple languages and automated image optimization.
Simplicity with flexibility: Astro lets you get content out fast and at scale, without tripping up on detail or complex configuration challenges. However, it also has customization potential when you need to tweak pages, or layer interactivity on top of static HTML.
Load priorities: Astro is capable of prioritizing the order in which it loads its island architecture. This means that more important page components, such as page headers and image headers, can be prioritized over less important components such as sidebar or footer content, or the comments section.
Ultimately, Astro JS is for web developers that need to combine speed and dynamism, without compromising the depth and richness of the content that they want to display. The framework lets you start simple both in terms of resources and expertise, and layer complexity onto static sites, including interactive components, as and when you need to.
On the other hand, if you’re a more experienced web developer, aren't interested in developing a static-HTML site, or have a project that you know will have a very high level of interactivity or complex display requirements, Astro might not be the web framework for you. In those cases, it's worth considering your options with alternatives like Next.JS, Vue.js, or React.
And that's all folks! We've gone on a little tour of Astro with all its funky features, and we've created a website to support an imaginary conference. That should be plenty to get you started. And don't forget you can find the complete code on GitHub.
Subscribe for updates
Build better digital experiences with Contentful updates direct to your inbox.