Install Astro and Build Your First Page
A practical walkthrough for scaffolding an Astro 5 project — installing Node.js, running npm create astro, understanding the file layout, writing your first .astro page, and producing a production build.
What you'll learn
- ✓How to install Node.js the right way in 2026
- ✓How to scaffold an Astro 5 project with npm create astro
- ✓What every file in a fresh Astro project actually does
- ✓The two parts of a .astro file — frontmatter and template
- ✓How to run the dev server and produce a production build
Prerequisites
- •A first reading of What is Astro?
- •Comfort with the terminal and HTML basics
This post takes you from a blank computer to a running Astro 5 site in roughly ten minutes. We use the official create astro scaffolder and write a first page from scratch.
Step 1: Install Node.js
Astro’s tooling runs on Node.js. You need Node 20 or newer — Node 22 is the current LTS as of 2026.
Check whether you already have it:
node --version
If you see v20.x.x or higher, skip to step 2. Otherwise install Node from one of these:
- macOS / Linux — a version manager like
fnmornvmis the cleanest option. - Windows — download the LTS installer from nodejs.org.
Verify both Node and npm are available:
node --version # v22.x.x
npm --version # 10.x.x
npm is the package manager bundled with Node. pnpm and Bun work too — every command below has equivalents.
Step 2: Create an Astro project
Pick a directory where you keep code, then run:
npm create astro@latest my-astro-site
The scaffolder asks a few questions. Sensible answers for this series:
? How would you like to start? › Empty project
? Install dependencies? › Yes
? Initialize a new git repository? › Yes
? Do you plan to write TypeScript? › Yes
? How strict should TypeScript be? › Strict
We pick TypeScript even though we will not lean on its advanced features. Astro’s content collections and component props are far better with it on, and turning it off later is harder than leaving it on.
Once the scaffolder finishes:
cd my-astro-site
npm run dev
Open the URL it prints — usually http://localhost:4321. You should see a near-empty starter page. That is a working Astro 5 site.
Step 3: Tour the project
Open the project in your editor. The file tree looks like this:
my-astro-site/
├── node_modules/
├── public/
│ └── favicon.svg
├── src/
│ ├── assets/
│ ├── components/
│ ├── layouts/
│ └── pages/
│ └── index.astro
├── astro.config.mjs
├── package.json
├── tsconfig.json
└── README.md
A short tour of every directory you will touch.
src/pages/
The most important folder in the project. Every file here becomes a route.
src/pages/index.astro→/src/pages/about.astro→/aboutsrc/pages/blog/index.astro→/blogsrc/pages/blog/[slug].astro→/blog/anything
There is no router to configure. The filesystem is the router.
src/components/
Reusable .astro components. Nothing in this folder becomes a route — components only render when something imports them. We cover this in Astro Components and Layouts.
src/layouts/
Layout components — the shared wrapper around every page. The starter does not create one by default; you make it yourself in the next post.
public/
Static files that get copied to the output untouched. Put favicon.svg, robots.txt, and any images you do not want Astro to process here.
astro.config.mjs
Astro’s configuration. The starter is almost empty:
import { defineConfig } from 'astro/config';
export default defineConfig({});
You will edit this later to add integrations — @astrojs/react, @astrojs/mdx, @astrojs/sitemap. For now leave it alone.
package.json
The project manifest. The scripts that matter:
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
}
npm run dev— the development server you are already runningnpm run build— produces a static site indist/npm run preview— serves the production build locally
Step 4: Anatomy of a .astro file
Open src/pages/index.astro. The contents look something like this:
---
// Frontmatter — runs at build time on the server
const title = "Welcome";
---
<html lang="en">
<head>
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
</body>
</html>
Every .astro file has two parts.
1. The frontmatter — between the --- fences at the top. This is plain JavaScript (or TypeScript) that runs at build time. You can import modules, fetch data, define constants. None of this code reaches the browser.
2. The template — everything below the fences. HTML, with {expressions} for JavaScript values, and component tags for nested components. This is what the visitor receives.
The mental model: frontmatter runs once on your machine, the template is what gets shipped.
Step 5: Write your first page
Replace src/pages/index.astro with this:
---
const title = "My Astro Site";
const links = [
{ href: "/about", label: "About" },
{ href: "/blog", label: "Blog" },
];
---
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{title}</title>
</head>
<body>
<h1>{title}</h1>
<nav>
<ul>
{links.map((link) => (
<li><a href={link.href}>{link.label}</a></li>
))}
</ul>
</nav>
</body>
</html>
Save the file. The browser updates automatically — that is Astro’s hot module reload. Notice three things:
{title}interpolates a variable into the template{links.map(...)}runs JavaScript inside the markup, exactly like JSX- The
<li>does not need akeyprop — Astro is server-rendered, not virtual-DOM
Now create a second page. Make src/pages/about.astro:
---
const name = "Ada";
---
<html lang="en">
<head><title>About</title></head>
<body>
<h1>About</h1>
<p>Hello, I'm {name}.</p>
<p><a href="/">Back home</a></p>
</body>
</html>
Visit http://localhost:4321/about. The page is there. You did not configure a route — creating the file was the configuration.
Try it yourself. With the dev server running, add src/pages/contact.astro with a heading and a paragraph. Save. Visit /contact. Confirm the file appears as a route without restarting anything.
Step 6: Build for production
When you are ready to deploy:
npm run build
Astro writes a static site to dist/. To preview it locally:
npm run preview
The dist/ folder is what you upload to any host — Netlify, Vercel, Cloudflare Pages, GitHub Pages. Astro sites are static by default, so any static host works.
If you open dist/index.html directly, you can read the rendered HTML. Notice there is no JavaScript bundle referenced — exactly as promised. Just HTML and CSS.
Things that commonly trip people up
- Port already in use — Astro picks
4322,4323, etc. automatically. Use the URL it prints. Cannot find module 'astro'— you forgotnpm installafter cloning the project. Run it.- Frontmatter code shows in the page — the
---fences must be on their own lines at the very top of the file. - Page does not appear under the URL you expect — the filename and folder path are the URL.
src/pages/About.astrois/About, not/about. Astro is case-sensitive. - JSX-like errors —
classbecomesclass:listonly when you want conditional classes; plainclassis fine in.astrofiles.
Useful editor setup
Two things to install on day one:
- Astro VS Code extension — syntax highlighting, IntelliSense in frontmatter and template, prop autocomplete
- Prettier with prettier-plugin-astro — formats
.astrofiles cleanly
With these two, the editor experience is on par with React in VS Code.
Try it yourself. Add a <style> block inside one of your pages and write a few CSS rules. Astro scopes styles to the component automatically — meaning the same h1 selector in two pages will not collide. Verify by setting different colours in index.astro and about.astro.
Recap
You now have:
- Node 20+ installed and verified
- A fresh Astro 5 project scaffolded with
npm create astro - An understanding of
src/pages/,src/components/, andastro.config.mjs - The two-part anatomy of a
.astrofile — frontmatter and template - A multi-page site running on the dev server
- A production build command that emits a static
dist/
Next steps
The next post zooms into the unit you will spend most of your Astro life writing: the component. We cover props, slots, layouts, and the BaseLayout pattern every Astro project converges on.
→ Next: Astro Components and Layouts
Questions or feedback? Email codeloomdevv@gmail.com.