Developers often claim that the most challenging task in development is choosing good variable names. However, before reaching that point, it is crucial to select the right development tools, libraries, and frameworks that will enhance performance, streamline the development process, and provide a better user experience.
The vast number of frameworks available makes this decision even more complicated, often leading to choice fatigue. JavaScript is particularly affected, with new frameworks, tools and libraries frequently entering the ecosystem.
One of these frameworks is Astro, which ranks second in the 2023 JavaScript Rising Stars survey and is often referred to as the "framework of all frameworks.". This article will explore Astro, its features, why it is called the "framework of all frameworks," and how to get started.
#What is Astro?
Astro is an open-source web framework created by Fred Schoot in 2021 to build fast, performant, content-driven websites.
Astro is well known for its performance, which is largely hinged on its static-first architecture. This architecture renders websites without any JavaScript, significantly reducing load times. However, Astro’s popularity in the developer ecosystem can be traced to its framework-agnostic approach, which allows developers to choose their preferred tools while still benefiting from Astro's features.
In the next section, let’s explore these features in more detail.
#What’s unique about Astro?
Astro is unique among existing JavaScript web frameworks, and by exploring its features, you’ll discover why.
Island architecture
Island architecture, also known as Astro islands, is a metaphor for frontend architecture that conveys two key concepts: separation of concerns and independent functionality.
In Astro, most web pages are pre-rendered as static HTML at build time, minimizing unnecessary JavaScript. Interactive components, like widgets or dynamic content, are isolated as "islands" within the static content, loading only the necessary JavaScript for their specific functionality. This keeps the bulk of the webpage fast and lightweight. Examples of solutions using this include Deco and Dodonut.
For instance, a blog with a static layout can have interactive elements like a search bar or comment section as separate islands with their own JavaScript, ensuring lightweight websites. Astro also uses partial hydration, where only the interactive parts of a webpage are made dynamic, further optimizing performance.
Outputs no JS by default
JavaScript is one of the web's three core pillars and is crucial for web interactivity. However, it can slow down initial page loads, especially for content-heavy sites.
Many frameworks rely heavily on JavaScript for rendering and interactivity. However, Astro takes a different approach by defaulting to zero JavaScript output. Astro sends only HTML and CSS to the browser when a webpage loads. JavaScript is included only if explicitly needed, enhancing performance significantly. This approach also improves SEO, as search engines can easily index static content, potentially boosting site visibility.
Server side approach
By default, Astro operates as a Static Site Generator (SSG), which means the website's pages are created as static HTML files during the build process. These static files are typically stored on a Content Delivery Network (CDN) and are then served directly to the user's browser, resulting in faster loading times.
In addition to SSG, Astro supports Server-Side Rendering (SSR). In SSR mode, the server dynamically generates HTML for each page upon request. This capability is beneficial for applications requiring real-time data updates or personalized content.
Agnostic to UI libraries and frameworks
Most JavaScript frameworks enforce the use of a specific UI library. For example, choosing Next.js generally restricts developers from using React libraries, preventing them from using Vue libraries within the same project.
Astro, however, is not a frontend framework as it does not mandate the use of any specific UI library or framework-specific capabilities. With compatibility built into its core, Astro allows developers to choose and combine various libraries and frameworks, such as React, Vue, and Svelte, to suit their project’s needs.
This flexibility means developers do not need to learn a new library from scratch and can reuse existing components from different frameworks within Astro.
#Comparison to other frameworks
Astro is often referred to as "the framework of all frameworks" because it uniquely combines the strengths of multiple JavaScript frameworks while addressing some of their common drawbacks, like vendor lock-in and performance overhead of frameworks like Nuxt.js.
Here is a breakdown of how Astro compares to other popular frameworks across some key features:
Comparisons | Astro | Nuxt.js | Gatsby | Next.js |
---|---|---|---|---|
SSR | ✅ | ✅ | ✅ | ✅ |
SSG | ✅ | ✅ | ✅ | ✅ |
Partial hydration | ✅ | ❌ | ❌ | ❌ |
Island architecture | ✅ | ❌ | ❌ | ❌ |
Choosing the best framework depends on each project's requirements. While Next.js, Nuxt.js, and Gatsby shine for their SSR and SSG capabilities, Astro distinguishes itself by combining these strengths into a single tool, especially for content-focused websites and websites prioritizing performance and efficiency.
#Basic step for setting up an Astro project
Setting up an Astro project can be done via the command line. Here is a step-by-step guide to get started:
1. Prerequisites
The following are required on your computer to get started:
- Node.js(Version 18 or higher)
- Basic knowledge of JavaScript
- An integrated development environment (IDE) like VSCode
2. Creating an Astro project
First, create an Astro project using:
npm create astro@latest
Running the command above will prompt you to select from several options.
Choose the options that best fit your project. Next, switch to the project folder you created and open in your IDE.
To run the project in developer mode, run npm run dev
in the CLI. This will provide a URL showing the Astro project when opened in the browser.
#Project structure in Astro
Understanding Astro’s organized project structure is crucial for efficient development. Astro’s structure provides clear code organization, which allows the developer to focus on building and improving the site rather than managing a disorganized codebase.
Folder structure
An Astro project directory after creation will look like this:
/my-astro-project├── node_modules/├── public/├── src/│ ├── components/│ ├── layouts/│ ├── pages/├── env.d.ts├── .gitignore├── astro.config.mjs├── package.json├── package-lock.json├── README.md└── tsconfig.json
As seen above, the Astro root folder consists of various directories and files. Let us examine some of these directories.
public/
: This contains the static files that do not need processing.src/pages/
: The files here are automatically turned into routes.src/components/
: This stores the reusable components. For example, it may contain aHeader.astro
for the site’s header.src/layouts/
: Layouts help structure the pages. A typical example isMainLayout.astro
, which might include a header, footer, and slot for page content.
The src
directory contains the project source code and is where most of the development time will be spent.
Routing
Astro's routing is designed to be simple and intuitive. It achieves this through file-based routing. At the basic level, all routing between pages uses the standard HTML <a>
tags with the href
attribute pointing to the specified route. However, Astro also supports other types of routing, like dynamic and static routing.
Static routing involves converting all files in the src/pages
directory with the .astro
, .md
, or .mdx
extensions into static pages. For example, src/pages/blog.astro
becomes /blog
.
On the other hand, dynamic routing involves using square brackets []
to create routes that can handle variable segments in the URL. For example, src/pages/blog/[slug].astro
would match any URL starting with /blog/
, followed by any value such as /blog/first-post
. The value inside the brackets becomes a parameter that can be used in the page code.
Beyond this, creating nested routes using folders within src/pages
is also possible.
As seen in all the examples above, Astro does not need any special configuration to create routes. Similar to Next.js or Nuxt.js, one can easily set up the routes, by simply organizing files within the src/pages
directory.
Pages
Pages constitute the routes are found in the src/pages/
directory of any Astro project. Each page in Astro is created as a .astro
file, with each of these files representing a different view or sections that users navigate to on the website. For example:
index.astro
corresponds to the homepage (/
)about.astro
corresponds to the about page (/about
)
This file-based structure in Astro directly correlates with the URL paths of the web application, which ensures clarity and ease of development.
Components
Astro components are reusable, self-contained units of code that encapsulate parts of the user interface, similar to those in modern web frameworks like Next.js and Nuxt.js. They support various JavaScript frameworks, allowing developers to use React, Vue, Svelte, and others alongside Astro’s native components.
Astro’s native components use the .astro
file extension and are typically located in the src/components
directory. They resemble HTML files but include additional features like frontmatter, slot support, and scoped CSS.
A simple Astro component will look like this:
---// Frontmatter sectionconst title = "Hello, World!";---<style>h1 {color: purple;}</style><h1>{title}</h1><p>This is an Astro component!</p>
In the example above, a constant title
was defined in the frontmatter with the value "Hello, World!". Scoped CSS was added to style the <h1>
element, ensuring the styles apply only to this component. Finally, HTML that uses the title
variable was included.
To use this component elsewhere, write:
---import Greeting from '../components/Greeting.astro';---<Greeting />
This approach supports Don't Repeat Yourself (DRY) principles and separation of concerns.
Layouts
Layouts found in src/layouts
in an Astro project allow developers to define a common and consistent design and structure, such as headers, footers, or navigations, that can be reused across different pages, ensuring that the website has a cohesive look and feel.
While layouts and components are essential in an Astro project, components handle reusable UI elements while layout manage the overall page structure.
Layouts contain a <slot/>
element, which acts as a placeholder for injecting each page's unique content. Let us explore a simple layout example.
<header><h1>Hygraph</h1><nav><a href="/">Home</a><a href="/about">About</a></nav></header><main><slot /></main><footer><p>© 2024 Hygraph</p></footer>
Next, developers can use the structure defined above in pages. Like so:
---import WebsiteLayout from '../layouts/WebsiteLayout.astro';---<BaseLayout><h2>Welcome to My Website</h2><p>This is the home page.</p></BaseLayout>
Developers can also create multiple layouts for different sections of the site. For instance, one might have a blog layout for blog posts and another for other parts of the website.
Styling
Styling in Astro is flexible, and developers can use various methods to apply CSS to any components and pages. This flexibility is beneficial as it lets developers choose the approach that best fits the project's needs - whether it is scoped CSS within components (as seen in an earlier example), global styles, or CSS frameworks like TailwindCSS.
Images
Images are crucial for any website's visual appeal and user experience. Astro supports the standard HTML <img>
tag for static images but offers a built-in <Image/>
component for optimizing larger images and improving performance.
Astro also enables resizing images with CSS attributes like width
and height
, and supports lazy loading for improved loading times.
To meet accessibility standards, Astro requires the alt
attribute for all images. For decorative images, Astro recommends using empty quotes “alt=""
” to indicate their purpose without disrupting screen reader experiences.
#Integrations and extensibility
Astro’s is called the "framework of all frameworks" because of its flexible and extensible design, which allows smooth integration with various tools, libraries, and services. This section explores how Astro can be integrated and extended to suit different project needs.
Integrating other frameworks
Astro adheres to a “bring your favorite tools” philosophy, which can account for part of its growing popularity. To allow this, Astro provides official integrations for various libraries and tools like Vue, React, and more. These integrations can be installed using one of the following methods:
- Using the
astro add
command:
npx astro add <framework>
In this case, add React by running npx astro add react
. Running this command will give you a couple of prompts, which, after responding, will add the desired framework to the project.
- The second option is through manual integration. This involves adding the integration to the
integrations
property in theastro.config.mjs
file. Like so:
//astro.config.mjsimport { defineConfig } from 'astro/config';import react from '@astrojs/react';export default defineConfig({ integrations: [react()], });
This will add the required dependencies needed to run React in an Astro project.
Once the integration is installed, one can create, import, and use components from the respective framework within Astro components. Here is an example of creating and using a React component in Astro:
// src/components/Counter.jsximport { useState } from "react";const Counter = () => {const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);};export default Counter;
First, a file called Counter.jsx
was created, and the code above was created. This code creates a counter component in React that displays the number of times a button is clicked.
To use this component in an Astro file, do the following:
---import Counter from '../components/Counter.jsx';---<Layout title="Welcome to Astro."><main><h1>Click Me!</h1><Counter client:load /></main></Layout>
To make any framework component interactive, you need to use a client:
directive, which specifies when the component's JavaScript should be sent to the browser. Similarly, in the above code, client:load
directive was added, which ensures the component is hydrated on the client side after the initial page load.
Editor's Note
.jsx
. Every framework used in Astro must adhere to its extension. For Vue or Svelte components, the respective file extensions (.vue
or .svelte
) would be used.Refer to the Astro integration guide for more detailed information and other integration options.
Fetching data
Fetching data from external or internal sources and interacting with APIs is a core part of building any modern web solution. Astro supports this natively using the fetch
function, which provides a familiar way to make HTTP requests to APIs.
Here’s a basic example of how to use the fetch
function in an Astro component:
---const response = await fetch('https://api.example.com/data');const data = await response.json();---
In this example, the fetched data can be used within the component as needed.
The fetch
function in Astro is versatile. It can query both REST and GraphQL APIs. It is available within any Astro or external components to retrieve data asynchronously. This flexibility helps to integrate data fetching seamlessly into Astro projects.
A Content Management System (CMS) proves helpful here as it simplifies content creation and management.
Managing content from a CMS
Integrating CMS with Astro is useful for sites that require frequent content updates without compromising performance. While the CMS handles content creation and storage, Astro supports SSG and fetches the data from the CMS for display on the website.
The workflow for integrating any CMS with Astro typically involves:
- Selecting a suitable CMS
- Installing the Astro integration package
- Configuring the CMS client within the Astro project
- Using integration functions to fetch and display content.
Best practices for using any CMS with Astro include implementing caching strategies to optimize performance and setting up error handling for reliable data access.
Now, let us pick a CMS and integrate it with Astro.
Pulling content from Hygraph via GraphQL
Choosing the right CMS is crucial for the business. In this section, you will use Hygraph, a headless CMS that uses GraphQL for content delivery.
To get started, sign up for a free-forever developer account on Hygraph. Hygraph also provides starters for Astro, and for this section, SKNCRE starter—a composable cosmetics brand e-commerce demo will be used.
Setting up the Hygraph project
Clone the project: Clone the SKNCRE starter project. It may take a while, but once cloned, open the project.
Configure API access: Navigate to Project Settings > API Access > Public Content API. Here, configure the Public Content API permissions to allow read requests without authentication. If you haven't already, click “Yes, initialize defaults” to add the required permissions for the “High Performance Content API.”
Set environment variable: In the same section as the above, locate the High Performance Content API and copy the URL. Next, create a
.env
file in the Astro root project you created before and add the URL, like so:
`HYGRAPH_HIGH_PERFORMANCE_ENDPOINT=***`
Now, Hygraph is successfully connected to your Astro project.
Before working on the Astro project, let us explore the cloned Hygraph project. To do this, navigate to the Hygraph’s API playground and explore the available content. In this case, you will query the products with a focus on specific parameters, such as:
query MyQuery {products {namepriceshortDescriptionstockimages {urlalt}}}
Running the query in the API playground displays the response in the pane. This content is sourced from the Hygraph project and its accessible via the “Content” view.
Next, execute the same query in the Astro project and showcase the content in the UI.
Querying data from Hygraph
Follow this installation guide to create a new Astro project that uses Tailwind for styling.
Next, install the GraphQL client for fetching data:
`npm add graphql-request`
Now, create the first Astro component named ProductItem.astro
and add this to the file:
---import { Image } from 'astro:assets';export interface Product {name: string;price: number;shortDescription: string;stock: number;images: {url: string;alt: string;}[];}const { name, price, shortDescription, stock, images } = Astro.props;---<div class=" border border-stone-300 border-solid p-4 mb-4"><div class="flex">{images.map((image) => (<Image src={image.url} alt={image.alt} width="50" height="50" loading="lazy" class="w-1/4 mr-2"/>))}</div><h2 class="text-2xl my-2 capitalize">{name}</h2><p class="mb-2">{shortDescription}</p><p class="font-bold mb-2">Price: ${price}</p><p class="mb-2">Stock: {stock}</p></div>
In the above code:
- An interface was declared to specify the expected shape of product data as props, including fields like name, price, short description, stock, and an array of images
- These properties were then destructured from
**Astro.props**
for use within the component - Finally, the HTML section was created to display the data, styling it with CSS.
Next, let us create another component named **ProductList.astro**
and add the code below:
---import ProductItem from './ProductItem.astro';export interface Product {name: string;price: number;shortDescription: string;stock: number;images: {url: string;alt: string;}[];}const { products } = Astro.props;---<div class="flex md:flex-row flex-col gap-4 justify-between">{products.map((product: Product) => (<ProductItem {...product} />))}</div>
Here, a ProductItem
component was imported, and a Product
interface was defined to structure the product data. The component receives a list of products via Astro.props
and renders each product using the ProductItem
component, displaying them in a flexible and responsive layout.
Fetching and displaying data
Now, let us bring it together by adding the code below to the index.astro
:
---import { GraphQLClient } from "graphql-request";import ProductList from '../components/ProductList.astro';// Create a new GraphQL client with the Hygraph endpointconst client = new GraphQLClient(import.meta.env.HYGRAPH_HIGH_PERFORMANCE_ENDPOINT);// Declare Products typetype Product = {name: string;price: number;shortDescription: string;stock: number;images: {url: string;alt: string;}[];};type Products = {products: Product[];};// Fetch the data via the GraphQL queryconst { products }: Products = await client.request(`query MyQuery {products {namepriceshortDescriptionstockimages {urlalt}}}`);---<html lang="en"><head><meta charset="utf-8" /><link rel="icon" type="image/svg+xml" href="/favicon.svg" /><meta name="viewport" content="width=device-width" /><meta name="generator" content={Astro.generator} /><title>Astro</title></head><body><div class="m-12"><h2 class="mb-8 text-5xl font-bold">Available Products:</h2><ProductList products={products} /></div></body></html>
In this code, the following was achieved:
- Imported the GraphQL Client installed in earlier steps and the
ProductList
component created earlier - Initialized the GraphQL client using the endpoint stored in the environment variable
HYGRAPH_HIGH_PERFORMANCE_ENDPOINT
- Defined the TypeScript types for the product and list of products
- Fetched the product data from Hygraph using the GraphQL client
- Destructured the data to extract the
products
- Used the
ProductList
component to render the fetched products, passing theproducts
array as a prop
Editor's Note
At this point, our UI should look like the below:
After exploring seamless data fetching from Hygraph headless CMS in an Astro project, there is much more developers can achieve with Hygraph and Astro in terms of content management
#Deploying Astro
Now that you have created the project, the next step is to deploy it so users can access it online. To achieve this, Astro supports various deployment options, including Netlify, GitHub Pages, Vercel, and more.
In this guide, you will use Vercel to deploy the application. The application built is a static site, and since Astro generates static sites by default, the deployment process is straightforward and requires minimal configuration.
Vercel offers two deployment methods: the Vercel UI and the Vercel CLI. Here, the focus will be on Vercel UI.
Steps to deploy using Vercel UI
- Ensure the Astro project is pushed to a Git repository, like GitHub. Find the project you created in this GitHub repository
- If you don't already have one, sign up for a Vercel account
- Log in to Vercel and click on "Import Project". Then, select the Git repository where the Astro project is pushed. Vercel will automatically detect the framework (Astro) and set up the project accordingly
- Add the environment variables as needed and deploy
Once the deployment is complete, you will see a message indicating the application the deployment status. In our case, the deployed application can be accessed via this Vercel link.
For guidance on deploying Astro projects to Netlify, refer to the Astro-Hygraph deployment documentation.
Now that you have successfully deployed the project, let's consider the cases where Astro is most suitable.
#When to use Astro
Astro stands out for its numerous features, which have been explored in previous sections. However, there are some cases where Astro excels more than other frameworks. Some of these include:
- Content-focused websites: Astro’s SSG features ensure pages load swiftly by pre-rendering HTML during the build process. This makes it ideal for content-heavy websites that serve a lot of static content, such as documentation sites, where the primary focus is delivering static content quickly.
- SEO-focused websites: Astro's ability to output no JavaScript by default enhances page load times and improves SEO. Faster-loading pages have more chances to rank higher in search engine results, making Astro a great choice for websites that rely heavily on search engine visibility.
- Performance-centric websites: Astro's focus on SSG and minimal JavaScript by default leads to blazing-fast loading times, making it a great choice for websites where performance is paramount. This ensures a better user experience and lower bounce rates.
- Integrating with Headless CMSs: Astro's compatibility with headless CMSs like Hygraph makes Astro a great choice for projects that require efficient content management and seamless integration with a headless CMS.
- Flexibility preference: Astro's agnostic nature towards UI libraries and frameworks allows developers to use React, Vue, Svelte, or other frameworks together. This flexibility is beneficial for projects that require integrating various technologies or for teams with diverse expertise.
#When not to use Astro
While Astro is a powerful and versatile framework, there are certain scenarios where it might not be the best development option. Some of these include:
- Single-Page Applications (SPAs): Astro is a Multi-Page Application framework. As such, it is not well suited for highly interactive SPAs where client-side routing is crucial. In this case, React or Vue might be more suitable.
- Applications with complex state management: Astro might not be the best fit for applications with complex state management requirements and heavy client-side interactions compared to Nuxt.js or Next.js.
- Heavy client-side computation: Applications that require heavy client-side computation, such as data visualization or complex calculations, may not benefit from Astro's strengths. In these cases, an SPA framework with more client-side capabilities might be a better fit.
Astro is not a one-size-fits-all solution; it is important to know where its strengths lie and when it is best to use a different framework.
#Tips and best practices
Having explored various aspects of Astro, let’s look at some recommended practices that will enhance your product
- When working with images, place images in the
src
folder rather than thepublic
folder. This allows Astro to process and optimize images, enhancing performance. Files in thepublic
folder are not processed, which can lead to performance declines. - Leverage the frontmatter in the Astro files to include metadata such as titles, descriptions, and other SEO-related information. Properly structured metadata helps improve the site's SEO,
- Use scoped CSS within Astro components to avoid style conflicts and ensure that components are styled independently. This approach adheres to the principle of separation of concerns, making the codebase cleaner and more maintainable.
- While Astro provides built-in SEO features, it is also beneficial to use semantic HTML elements like
<section>
,<nav>
, and<article>
. These elements enhance accessibility and improve SEO. - Astro is under active development. Follow the official Astro channels and regularly check the releases to stay updated with the latest features, improvements, and bug fixes.
#Wrapping up
This article explored Astro, highlighting its importance and best use cases. A practical example using Hygraph demonstrated how to leverage Astro's static site generation capabilities. However, this is just the beginning of what one can achieve with Hygraph.
To explore the full range of possibilities with Hygraph, consider watching Hygraph's Head of Developer Relations, Bryan Robinson’s guides on "Building Websites with Astro and Hygraph Part 1" and "Building Websites with Astro and Hygraph Part 2."
Additionally, join Hygraph’s developer workspace to connect with other users and the Hygraph team.
Blog Author
Motunrayo Moronfolu
Technical writer
Motunrayo Moronfolu is a Senior Frontend Engineer and Technical writer passionate about building and writing about great user experiences.