This post outlines the top 5 coolest things about Astro, and why you might want to consider it for your next project
At the end, I'll share a demo of a project I used Astro for, and how I found working with it
Intro
If you're new to Astro, in short it's a framework for generating very optimized, websites to be rendered by the server or statically generated. No heavy JavaScript needs to be sent to the client, nor is it needed for rendering. This gives your site a huge boost in performance, SEO, accessibility and user experience.
As well as that, you're not locked into a single cloud provider, frontend framework, backend CMS or anything else. Pretty much all the features you could need for any sort of site, or any size are included, either out-of-the-box, or as 1-line integration.
Astro is super easy to get started with, and an absolute joy to work with. The developer experience is π€
If you're just interested in a demo of it in action, then βοΈ Skip to the End
Top 5 Cool Things about Astro π
Cool Thing 1 - Lightening Fast β‘
Unlike other frameworks, that primarily do all expensive rendering on the users browser, Astro uses server-side rendering and static site generation, boosting your performance metrics.
And it's super easy - just define the rendering mode by setting output
to either static
, server
or hybrid
at the top of any given file.
This is awesome, as you can get the balance between between speed and dynamic content.
- Pre-rendered: The static output will generate all HTML routes once, at build-time.
- On-Demand Rendering: The server output will render routes on the server, at the point the user requests them (similar to how PHP, .NET and other SSR technologies used to work).
- Hybrid: For mostly-static sites with some on-demand content, you can use hybrid output for on-demand rendering of certain features only.
Cool Thing 2 - DevEx π¨βπ»
With Astro, you get several really nice things out the box, without needing to install or configure anything extra.
Firstly, page transitions. Implementing is as simple as importing ViewTransitions
, adding <ViewTransitions />
to your layout file (or a common component), and adding the transition
attribute to any views/component you want to animate in/out.
Secondly, prefetch. Page load times play a huge role in the enjoyability of using any website. With prefetch enabled, the next page is automatically loaded in the background when the user is about to click the link, that way it can be displayed near-instantly. Usage is simple, in your config just set prefetch: true
, then add the data-astro-prefetch
attribute to any link you'd like to be pre-fetched.
Thirdly, there's first-class support for Typescript, built in environmental variable / .env support, CSS pre-processing (SASS/SCSS)
For building, Astro uses Vite, which if needed you can easily extend with the Vite or Rollup plugin.
Cool Thing 3 - UI Agnostic π
Now, you might be wondering how you're going to deal with interactivity, especially for statically generated sites. That's where islands come in.
The general idea is that you render your HTML on the server, but inject slots around highly dynamic regions, which are then hydrated on client-side once loaded.
You can build these interactive islands in pretty much any frontend framework or web component library you like. Astro has integrations for React, Svelte, Vue, Solid, Alpine, Lit and more.
This might sound a bit complicated, but Astro makes it stupidly easy.
Here's an example, run npx astro add svelte
. Then go ahead and import standard Svelte components into any Astro view or component. In the below code snippet, for a news site - the post content can be statically generated for great SEO and snappy load times, but the comments form is a dynamic island
---
import PostContent from '@/components/PostContent.astro';
import Comments from '@/components/Comments.svelte';
//...
// Get the slug/ID of post to render, and fetch it's contents
const postSlug = Astro.request.params.slug;
const content = await Astro.fetchContent(`../posts/${postSlug}.md`);
---
<Layout>
<Navbar />
<main>
<!-- Import and use standard Astro component (SSR or SSG) -->
<PostContent innerHTML={content}/>
<!-- Import dynamic component for comments/chat form (client) -->
<Comments client:load postSlug={postSlug} />
</main>
<Footer />
</Layout>
As you can see, you can simply import any component (normal React, Svelte, Astro etc) into your Astro page, and add the client:load
directive, to specify it should be loaded client-side. If the page is particularly large, use client:visible
instead, so it won't be hydrated until visible to the user. Or if you want to skip server-side rendering + hydration all together, use client:only
to only execute client-side.
If you have existing components, you can even mix and match - importing different types of components into a single Astro file. And you can pass Astro props or render slots to any of these components, as well as nest them.
Cool Thing 4 - Tooling & Integrations π οΈ
Take a look at astro.build/integrations, and you'll see the huge directory of plugins available.
As you can see, pretty much every aspect needed for a high-quality, modern and scalable website is included. Everything from SPA support, accessibility, performance, auto-sitemap, storybook, testing add-ons, data adapters, frontend frameworks (for islands), adapters for (super) easy deployment to nearly any cloud platform and hosting provider.
Setting up any of these is as simple as running one npx astro add __
command, which will automatically install, import and configure the integration.
Talking about the astro
command, this CLI util makes the end-to-end setup, development and deployment process is a joy. It handles everything from creating your app, managing integrations, generating optimized platform-specific production builds, deploying, and much more. No matter the size of your app, the dev server is very snappy, with near-instant build + refresh times.
There's a dev toolbar, which let's you audit, inspect and debug your Astro app.
The community is also very strong, there's plenty of themes and templates to get you started.
Cool Thing 5 - Content First π
Managing a content-first site can quickly become messy. That's not the case with Astro.
To start with, the project structure is very intuitive. You get file-based routing out of the box, where every file/directory inside of ./src/pages
relates to an endpoint. You can write your pages using either .astro
, .html
, .md
, .mdx
and .ts
/.js
Below is a simple markdown example. If this were saved in ./src/pages/my-page.md
then you'd be able to access it at https://my-site.com/my-page
---
layout: '../layouts/MySiteLayout.astro'
title: 'My Markdown page'
---
# Title
This is my page, written in **Markdown.**
Of course, there's catch-all, path params, error pages, redirects, etc. You'll likey use a reusable layout from ./src/layouts
too, which are extendable.
For content-heavy websites, you'll probably want to use Astro's content collections option. This provides some neat features for creating, managing, organizing all front matter, as well as automatic validation and type saftey.
As expected, usage is simple. Just place any content (like .md
, .mdx
, .yaml
, .json
files) within a directory of your choosing inside src/content
. Once you have a directory, you can start querying your data.
This is ideal if interacting with a headless CMS or pulling structured content from a remote source. You define collections in src/content/config.ts
, as well specifying each collections schema (or using a remote schema).
Astro uses Zod to validate every fileβs frontmatter within a collection and provide automatic TypeScript types when you go to query content from inside your project.
Once your content is setup, you can reference and query it in any Astro page. Tasks like generating routes automatically from content, providing search functionality, passing content as props and rendering content as HTML is all strait forward.
Bonus Cool Thing - It's Super Easy π
Astro is insanely easy to use, the learning curve is so shallow that you can cover all the core concepts, and get your first project up and running within a few hours.
Markup lives in .astro
files, a superset of HTML (any valid HTML is also valid Astro). The templating language is simple yet powerful, it takes all the best parts of the likes of Svelte and Vue', while also borrowing support for JSX expressions from React.
One big reason why Astro is able to be so much less-complex than other frameworks, is that it was designed to render on the server, not in the browser. That means that you donβt need to worry about: hooks (React), stale closures (also React), refs (Vue), observables (Svelte), atoms, selectors, reactions, or derivations. There is no reactivity on the server, so all of that complexity melts away.
If you're using server-side rendering, this can get tricky when you need to support multiple providers / want to avoid ventor lock-in. Vercel serverless functions works differently to Netlify Edge functions, Cloudflare Workers, AWS Amplify, Azure, Deno etc. Thankfully, with Astro you don't need to worry about any of this. Just add the Adapters you need, and deploy!
This has been a whistle stop tour of Astro. There's much much more to discover, so do take a look at their (very well-written) docs.
Demo π
I'd like to finish off by briefly demoing an app that I build with Astro - Awesome Privacy. The website is deployed to awesome-privacy.xyz if you're interested!
For this project, I compiled a list of privacy-respecting apps and services in a single YAML file, each including a name, description, and a link to the project's website and GitHub repo.
- I made an Astro API route to fetch and parse this data.
- Then I used dynamic routes, so that there was a page for each category, section and listing.
- For example, /productivity --> /productivity/digital-notes --> /productivity/digital-notes/standard-notes
- Then, when you click a listing, I fetch data about the services privacy policy, website security, mobile app trackers, source code info, Docker metrics, social presence and more. As an example, see the Bitwarden page.
- Thanks to Astro, all these fetch requests happen at build-time, so there's no ongoing load on the backend, and the site is near-instant despite the amount of data fetched.
- I implemented site-wide search, at /search and results, at /search/[search-term]
- I added some additional routes to make the site more complete, including
- For viewing all listings: /all
- Your saved listings: /inventory
- And an about page: /about
The site has over 500 pages (you can see a full list here). But the cool thing is, all the content that defines and makes up all these pages is coming from a single YAML file. Astro is perfect for generating all these static routes, from one simple codebase.
I also made a quick API (at api.awesome-privacy.xyz - here's the code), but that was built with Hono and Cloudflare Workers, so it's a post for another day!
Originally the Awesome Privacy reop was just a markdown document. I wanted to preserve the ability to view all listings in the main README, while also keeping data synced across the website and GitHub repo. For this I used my YAML file as the single source of truth, then wrote a quick Python script (awesome-privacy-readme-gen.py) to convert the YAML into neatley formatted markdown content and insert into the README. This process runs via GitHub Actions, so whenever the YAML is updated, the README will automatically reflect these changes too.
Below is an example, showing the input YAML, and the output webpage.
As you can see, from a small amount of user-submitted data, we're able to generate a quite comprehensive report on a given service (in this example, it's Signal Messenger).