Getting Started with Astro
What’s Astro? Astro is an open-source web framework created to build fast, performant, content-driven websites. What really sets Astro apart is its performance. As the Astro team puts it: "It should be nearly impossible to build a slow website with Astro." What makes this statement true is how Astro handles rendering and delivering your website. It prioritizes server-side rendering (SSR) and minimizes client-side JavaScript by default and the use of island architecture. Prioritizes server-side rendering (SSR) Astro's philosophy is: render on the server, ship minimal client-side JS. Static HTML Generation by Default: Astro components render to static HTML at build time. No JavaScript is sent to the browser unless you explicitly opt in. The Island Architecture Astro uses what’s called island architecture — a way to combine static HTML with interactive components... So what does that mean? Island architecture is a frontend rendering strategy where your webpage is mostly static HTML, but certain "islands" of interactivity are hydrated separately and only when needed. An island always runs in isolation from other islands on the page, and multiple islands can exist on a page. Client islands can still share state and communicate with each other, even though they run in different component contexts. By default, Astro will automatically render every UI component to just HTML & CSS, stripping out all client-side JavaScript automatically. These islands: Run independently of each other. Can still share state if needed. Only hydrate (i.e., load JavaScript) when you tell them to. Turning any static UI component into an interactive island requires only a client:\* directive. Astro then automatically builds and bundles your client-side JavaScript for optimized performance. --- import Counter from '../components/Counter.astro' import LoginForm from '../components/LoginForm.astro' --- Hello, Astro Astro offers several hydration directives to control how components behave: client:load: Hydrates the component immediately after the page loads. client:idle: Waits until the browser is idle, then hydrates the component. client:visible: Hydrates the component when it enters the viewport (lazy loading). client:media: Hydrates the component only when a specific media query matches. client:only: Does not render the component on the server—renders it only on the client. Getting Started with Astro To start a new Astro project, you'll need Node.js installed — version 18.17.1 or 20.3.0 or later. (v19 is currently not supported.) Step 1: Create Your Project Start by running the command: npm create astro@latest Choose the starter template you like or stick with the default. Follow the CLI prompts to configure your project. Step 2: Run the Dev Server npm install And then: npm run dev Your site should now be live at http://localhost:4321. Your file stucture should look like this: ├── public/ # Static assets like images, fonts, etc ├── src/ │ ├── components/ # Reusable components │ ├── layouts/ # Layout components to structure your pages │ └── pages/ # Astro pages that automatically become the routes of your website | # /pages/about.astro becuase the `/about` path └── astro.config.mjs # Configuration file for your Astro project Anatomy of an .astro File Astro components use the .astro file extension. Each file can include the following sections: 1- Frontmatter — for imports, variables, functions (between ---). 2-HTML/JSX-like syntax — for page structure and layout 3- Styles — scoped styles using tags 4- Scripts — optional blocks for browser-side logic --- // begin Frontmatter import Layout from '../layouts/MainLayout.astro'; import '../styles/utils.css'; const pageTitle = 'Homepage'; // end Frontmatter --- /* h1 will be blue in this page only without affecting the style of h1 that might be other pages*/ h1 { color: blue; } {pageTitle} document.body.style.backgroundColor = 'yellow'; The style tag accepts define:vars{{}}, whcih accepts an object of variables that could be used as CSS vars. --- const foregroundColor = "rgb(221 243 228)"; const backgroundColor = "rgb(24 121 78)"; --- h1 { background-color: var(--backgroundColor); color: var(--foregroundColor); } Hello World Using Slots and Props in Astro What Are Slots in Astro? If you've worked with React or Vue you should have an understanding of what slots (or childeren in React) mean. A slot is basically a placeholder for content that you pass into a component. It allows you to keep a consistent layout across multiple pages, while still injecting unique content where needed. Let’s take a look at a simple layout component that uses a slot: // layouts/Layout.astro --- import Header from "

What’s Astro?
Astro is an open-source web framework created to build fast, performant, content-driven websites.
What really sets Astro apart is its performance. As the Astro team puts it:
"It should be nearly impossible to build a slow website with Astro."
What makes this statement true is how Astro handles rendering and delivering your website. It prioritizes server-side rendering (SSR) and minimizes client-side JavaScript by default and the use of island architecture.
Prioritizes server-side rendering (SSR)
Astro's philosophy is: render on the server, ship minimal client-side JS.
Static HTML Generation by Default:
- Astro components render to static HTML at build time.
- No JavaScript is sent to the browser unless you explicitly opt in.
The Island Architecture
Astro uses what’s called island architecture — a way to combine static HTML with interactive components... So what does that mean?
Island architecture is a frontend rendering strategy where your webpage is mostly static HTML, but certain "islands" of interactivity are hydrated separately and only when needed.
An island always runs in isolation from other islands on the page, and multiple islands can exist on a page. Client islands can still share state and communicate with each other, even though they run in different component contexts.
By default, Astro will automatically render every UI component to just HTML & CSS, stripping out all client-side JavaScript automatically.
These islands:
- Run independently of each other.
- Can still share state if needed.
- Only hydrate (i.e., load JavaScript) when you tell them to.
Turning any static UI component into an interactive island requires only a client:\*
directive. Astro then automatically builds and bundles your client-side JavaScript for optimized performance.
---
import Counter from '../components/Counter.astro'
import LoginForm from '../components/LoginForm.astro'
---
<html>
<body>
<h1>Hello, Astro</h1>
<Counter client:load />
<LoginForm client:visible />
</body>
</html>
Astro offers several hydration directives to control how components behave:
client:load
: Hydrates the component immediately after the page loads.
client:idle
: Waits until the browser is idle, then hydrates the component.
client:visible
: Hydrates the component when it enters the viewport (lazy loading).
client:media
: Hydrates the component only when a specific media query matches.
client:only
: Does not render the component on the server—renders it only on the client.
Getting Started with Astro
To start a new Astro project, you'll need Node.js
installed — version 18.17.1
or 20.3.0
or later. (v19
is currently not supported.)
Step 1: Create Your Project
Start by running the command:
npm create astro@latest
Choose the starter template you like or stick with the default. Follow the CLI prompts to configure your project.
Step 2: Run the Dev Server
npm install
And then:
npm run dev
Your site should now be live at http://localhost:4321
.
Your file stucture should look like this:
├── public/ # Static assets like images, fonts, etc
├── src/
│ ├── components/ # Reusable components
│ ├── layouts/ # Layout components to structure your pages
│ └── pages/ # Astro pages that automatically become the routes of your website
| # /pages/about.astro becuase the `/about` path
└── astro.config.mjs # Configuration file for your Astro project
Anatomy of an .astro
File
Astro components use the .astro file extension. Each file can include the following sections:
1- Frontmatter — for imports
, variables
, functions
(between ---
).
2-HTML/JSX-like syntax — for page structure and layout
3- Styles — scoped styles using tags
4- Scripts — optional blocks for browser-side logic
---
// begin Frontmatter
import Layout from '../layouts/MainLayout.astro';
import '../styles/utils.css';
const pageTitle = 'Homepage';
// end Frontmatter
---
<style>
/* h1 will be blue in this page only without affecting the style of h1 that might be other pages*/
h1 {
color: blue;
}
</style>
<Layout>
<h1>{pageTitle}</h1>
<HeroSection />
</Layout>
<srcipt>
document.body.style.backgroundColor = 'yellow';
</srcipt>
The style
tag accepts define:vars{{}}
, whcih accepts an object of variables that could be used as CSS vars.
---
const foregroundColor = "rgb(221 243 228)";
const backgroundColor = "rgb(24 121 78)";
---
<style define:vars={{ foregroundColor, backgroundColor }}>
h1 {
background-color: var(--backgroundColor);
color: var(--foregroundColor);
}
</style>
<Layout>
<h1>Hello World</h1>
</Layout>
Using Slots and Props in Astro
What Are Slots in Astro?
If you've worked with React or Vue you should have an understanding of what slot
s (or childeren
in React) mean.
A slot is basically a placeholder for content that you pass into a component. It allows you to keep a consistent layout across multiple pages, while still injecting unique content where needed.
Let’s take a look at a simple layout component that uses a slot:
// layouts/Layout.astro
---
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
---
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>My Astro Site</title>
</head>
<body>
<Header/>
<slot />
<Footer />
</body>
</html>
The
tag is where the page-specific content will be injected. You can use the Layout.astro
component in any of your website pages to and replace the
tag with the main content of the page.
// layouts/contact-us.astro
---
import Layout from "../components/Layout.astro";
import ContactUsFrom from "../components/ContactUsFrom.astro";
---
<Layout>
<ContactUsFrom/>
</Layout>
// layouts/blog.astro
---
import Layout from "../components/Layout.astro";
import Posts from "../components/Posts.astro";
---
<Layout>
<Posts/>
</Layout>
- The
in theLayout
component will be
in the/contact-us
page and
in the/blog
path. - Both
/contact-us
and/blog
will have the sameLayout
.
Using slots gives you:
- Cleaner code: You avoid repeating headers, footers, or shared page structure.
- Reusability: One layout can be used across many pages.
- Flexibility: You decide exactly where dynamic content should appear.
What Are Props in Astro?
Props in Astro are values you pass to a component when you use it. Inside the component, you can access those values in the frontmatter section using regular JavaScript.
Think of it as function paramaters in Javascript. If you have sayHello
function that accetps a name
parameter, for example, a SayHello
componet in Astro, can also accept a name
prop to be used inside that component.
If you have a regular JavaScript function that accepts a name parameter:
function sayHello(name) {
return `Hello, ${name}`;
}
You can apply the same logic to Astro components:
// Example: src/pages/index.astro
// components/SayHello.astro
---
// get the name from the props in the Frontmatter section
const {name} = Astro.props;
---
<p>Hello, {name}!</p>
Now, we have a SayHello
component that can greet the user and this is how to use it:
---
import SayHello '../components/SayHello.astro';
const username = 'Hajar Nasr';
---
<SayHello name={username}/>
When you visit the page, it will render:
Hello, Hajar Nasr!
Fetching Data in Astro
Fetching data is simple — just use the fetch()
API inside frontmatter.
const response = await fetch('https://api.example.com/posts');
const posts = await response.json();
---
<ul>
{posts.map(post => (
<li>{post.title}</li>
))}
</ul>
Adding React to Your Astro Project
Astro supports multiple UI frameworks, including React, Vue, Svelte, Solid, and more. You can mix and match them in the same project.
To add React:
npm astro add react
Then update your config file:
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
});
Now you can create a React component and use it in your Astro pages:
// src/components/Counter.jsx
import { 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;
And in your .astro
file:
---
import Counter from '../components/Counter.jsx';
---
<Layout title="React in Astro">
<h1>Click the Button</h1>
<Counter client:load />
</Layout>