A Look at Building with Astro

Astro is a brand new framework for building websites. To me, the big thing is that it allows you to build a site like you’re using a JavaScript framework (and you are), but the output is a zero-JavaScript static site. You can opt-in to client-side JavaScript as needed, and there are clever options for doing so. Notably, the learning curve is somewhat flattened by the fact that it supports componentry you may already know: React/Preact (JSX), Svelte, Vue, or web components.

Table stakes
Starting a new project is as easy as it should be:
npm init astro
npm install
npm start
There is a helpful little process and output:
As expected (like you would get with Next or Nuxt or any other site builder kind of project) you get a dev server at a local port you can pop right up:
From here, I consider the table stakes to be CSS injection / Hot Module Reloading. No worries there:
A static site generator with honest-to-god real actual components
This is such a wonderful thing to me. I really like the idea of static site generators—I think they make a lot of sense in a lot of situations. Sending HTML over-the-wire is just a good move for resiliency, CDN-efficiency, SEO, accessibility, you name it. But in the past a lot of the options were either:
A JavaScript powered static site generator, that does generate a “static” site, but also ships a JavaScript bundle (e.g. Next or Gatsby)A static site generator that is more focused on HTML and has its own templating/formats that aren’t JavaScript components (e.g. Eleventy or Jekyll)I know there are exceptions, but this covers the vast majority of the site generator market.
But I want both!
I want to craft sites from JavaScript-components, because the syntax and tooling around them is just better than any other component system we have right now.I want static output that is actually zero-JavaScript (unless I manually opt-in to things).That’s what happens with Astro.
Those components?
They can be .jsx filesThey can be .svelte filesThey can be .vue filesThese are “renderers” and you can BYO. Astro also has it’s own format (.astro) and it’s also very compelling because:
It’s obviously a first-class citizen of how Astro worksIt’s comfortably JSX-like……except better because it does stuff like makes the work automaticallyStyled scoping works out of the box, through a normal

The “fences” (---) at the top is where the initial JavaScriptin’ goes. That’s where I yank in the props for this component if it needs any (they can be typed if you like that), do imports/exports, and set up data for the template below.
What feels a little funky, but is in-line with the Astro vibe, is that this is essentially Node JavaScript. It runs in the build process. So that console.log() statement I don’t see in my browser console, I see it in my command line.
pages-style routing
It’s tempting to say Next.js popularized this, but really the concept is as old as file systems. Think of how a classic Apache server works. If you have a file system like:
index.html
/about/
index.html
In a browser, you can visit http://website.com/about and that will render that index.html page under the /about folder. That’s what the routing is like here. By virtue of me having:
/pages/
index.astro
about.astro
I’ll have a homepage as well as an /about/ page on my site. That’s just a refreshingly nice way to deal with routing—as opposed to needing to build your own routing with component-ry all to itself.
If you want to do that thing where all the content of your site lives in Markdown files right in the repo, that’s a first-class citizen.
I think this is super common for stuff like blogs and documentation, especially as those are already popular targets for static site generators. And in these early days, I think we’re going to see a lot of Astro sites along those lines while people wait to see if it’s ready for bigger undertakings.
One way to use Markdown is to make Pages in Markdown straight away. The Markdown will also have “fences” (Frontmatter) where you chuck what layout you want to use (best to use an .astro file) and pass in data if you need to. Then the entire content of the Markdown file will flow into the . Pretty darn slick:
Another incredibly satisfying way to use Markdown in Astro is using the built-in component. Import it and use it:
---
import { Markdown } from 'astro/components';
---



# Hello world!

- Do thing
- Another thing in my *cool list*

Outside Markdown


You can also go snag some Markdown from elsewhere in your project and barf that into a component. That leads into fetching data, so let’s look at that next.
I suppose it’s kind of weird how Astro supports all these different frameworks out of the box.
I’ve overheard some pushback that Astro is inefficient at the npm install level since you have to bring down a bunch of stuff you likely won’t need or use. I’ve overheard some pushback on the idea that mixing-matching JavaScript frameworks is a terrible idea.
I agree it’s weird-feeling, but I’m not particularly worried about non-user-facing things. When things are happening only during the build process and all the user ever gets is HTML, use whatever feels good! If you ultimately do load the components-based frameworks to do on-page interactive things, surely it makes sense to limit it to one. And since you’re getting so much at build time, maybe it makes sense to use something designed for super light on-rendered-page interactivity.
Fetching data rules
We were just talking about Markdown so let’s close the loop there. You can “fetch” data internally in Astro by using fetchContent. Look how straightforward it is:
I fetch it the raw Markdown, then I could use the HTML it returns if I want, or slap it into a component if that makes sense for whatever reason:
---
import { Markdown } from 'astro/components';
const localData = Astro.fetchContent('../content/data.md');
---

But I don’t have to fetch internal data only. I’m a fan of Eleventy. During an Eleventy build, you can certainly go fetch data from an outside source, but I’d argue it’s a little finnicky. You fetch the data with code in a separate JavaScript file, pulling in your own network library, then processing and returning the data to use elsewhere in a template. Like this. In Astro, that fetching can happen right alongside the component where you need it.
Check out this real-world-ish example where I yank in data from right here from CSS-Tricks and display it as cards.
---
import Card from '../components/Card.astro';
import Header from '../components/Header';

const remoteData = await fetch('https://css-tricks.com/wp-json/wp/v2/posts?per_page=12&_embed').then(response => response.json());
---





CSS-Trickzz



{remoteData.map((post) => {
return(

)
})}



Check it out, I can build a page from CSS-Tricks data just that easily:
What’s fascinating about that is that the data happens:
in Node, not client-side, andduring the build process.So, in order to keep a website like this updated, I’d have to run the build/deploy process regularly.
Styling
Let’s say you want to use Sass to style your site. With many site generators, they punt on this, as a philosophy. Like saying “nah, we don’t want to be opinionated here, you style however you want to”. And I get that, it might be a strength as sometimes frameworks that are too opinionated lose people. But to me, it often feels unfortunate as now I’m on my own to wire up some style-processing build processes (e.g. Gulp) that I really just don’t want to deal with.
With Astro, the philosophy seems to be to support a wide swath of popular styling techniques out of the box right away.
Just import "./style.css"; vanilla stylesheetsUse a