# Getting Started with Astro

Course: [Astro](https://www.devtutorials.ai/learn/astro) · Section: Get Started
Source: https://www.devtutorials.ai/learn/astro/get-started/getting-started

> What Astro is and why it was created, its features, the HTML-first approach, what you can build, Astro vs Next.js and React, the ecosystem, system requirements, creating and running a project, its files, and the Astro CLI.

## Astro Introduction

- **Astro** is a tool for building websites.
- It is best for sites with a lot of content, such as blogs, docs and shop pages.
- It turns your code into plain HTML pages that load very fast.
- It adds JavaScript only to the parts of a page that need it.
- In this lesson, you will see what Astro is and create your first Astro site.

**Simple lesson:** Astro builds fast websites from plain HTML, and adds JavaScript only where you ask for it.

### A Real-World Example

- Asha is a computer science student in Chennai.
- She wants a personal site called **Asha's Dev Journal**.
- It will have a home page, an about page and many blog posts.
- Visitors only read the pages. Nothing needs to move or change.
- She wants it to open fast, even on a slow phone network.
- Astro is a good fit, because it sends ready-made HTML and almost no JavaScript.

Press **▶ Run** to build Asha's first page. Then click **HTML sent to browser** under the preview.

    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width" />
      <meta name="generator" content={Astro.generator} />
      <title>{siteName}</title>
    </head>
    <body>
      <h1>Welcome to {siteName}</h1>
      <p>Notes from my coding journey.</p>
      <p>Page built on {today}.</p>
    </body>
</html>
`,
  }}
/>

What happened:

- The part between the two `---` lines is the **component script**. It runs when the site is built.
- `{siteName}` puts the value of `siteName` into the page.
- The **HTML sent to browser** view shows only HTML. There is no `<script>` tag at all.

### What You Will Learn

In this lesson, you will learn:

1. What Astro is and why it was created.
2. The main features of Astro.
3. What "HTML first" and "zero JavaScript by default" mean.
4. What you can build with Astro, and when to pick another tool.
5. The Astro ecosystem: themes, Starlight and the docs.
6. What you need to install on your computer.
7. How to create, run, build and preview an Astro project.
8. What the main files and folders of a project do.

## What Is Astro?

- **Astro** = a web framework for building fast, content-driven websites.
- **Web framework** = ready-made code and rules that help you build websites faster.
- **Content-driven** = the site is mostly things to read or look at: text, images and lists.
- Astro is free and open source.
- You write pages in `.astro` files. They look like HTML with a few extras.

### HTML First

- A browser needs HTML to show a page.
- Many modern tools send JavaScript first. The browser then runs it to make the HTML.
- Astro does it the other way round. It makes the HTML before anyone visits.
- The visitor's browser gets a finished page. It can show it at once.

Watch the animation. Astro builds HTML once. Every visitor gets the same ready page.

<figure className="ast-fig ngc-fig">
<svg viewBox="0 0 660 210" role="img" aria-labelledby="fig-astro-build" style={{ width: "100%", maxWidth: 660, height: "auto" }}>
  <title id="fig-astro-build">Animation: .astro files go into Astro build, which makes HTML files. The HTML files travel to three visitors. The JavaScript meter stays at 0 KB.</title>
  <defs><marker id="ab-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0 L10 5 L0 10 z" style={{ fill: "var(--ngc-slate)" }} /></marker></defs>
  <g style={{ fontFamily: "var(--mono)", fontSize: 12, fontWeight: 700 }}>
    <rect x="16" y="40" width="120" height="30" rx="7" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)" }} />
    <text x="76" y="60" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>index.astro</text>
    <rect x="16" y="82" width="120" height="30" rx="7" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)" }} />
    <text x="76" y="102" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>about.astro</text>
    <rect x="16" y="124" width="120" height="30" rx="7" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)" }} />
    <text x="76" y="144" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>post.astro</text>
  </g>
  <text x="76" y="26" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>Your files</text>
  <rect x="190" y="62" width="120" height="70" rx="12" style={{ fill: "var(--ngc-orange)", stroke: "var(--ngc-orange)" }}>
    <animate attributeName="opacity" values="1;0.75;1" dur="1.5s" repeatCount="indefinite" />
  </rect>
  <text x="250" y="94" textAnchor="middle" style={{ fill: "#fff", fontFamily: "var(--sans)", fontSize: 16, fontWeight: 700 }}>astro build</text>
  <text x="250" y="114" textAnchor="middle" style={{ fill: "#fff", fontFamily: "var(--sans)", fontSize: 11 }}>runs once</text>
  <g style={{ fontFamily: "var(--mono)", fontSize: 12, fontWeight: 700 }}>
    <rect x="360" y="40" width="110" height="30" rx="7" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)" }} />
    <text x="415" y="60" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>index.html</text>
    <rect x="360" y="82" width="110" height="30" rx="7" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)" }} />
    <text x="415" y="102" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>about.html</text>
    <rect x="360" y="124" width="110" height="30" rx="7" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)" }} />
    <text x="415" y="144" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>post.html</text>
  </g>
  <text x="415" y="26" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>Finished pages</text>
  <path d="M136 97 H186" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#ab-arrow)" />
  <path d="M310 97 H356" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#ab-arrow)" />
  <g style={{ fontFamily: "var(--sans)", fontSize: 12, fill: "var(--ngc-slate)" }}>
    <text x="600" y="46" textAnchor="middle">👩 Visitor 1</text>
    <text x="600" y="102" textAnchor="middle">👨 Visitor 2</text>
    <text x="600" y="158" textAnchor="middle">🧑 Visitor 3</text>
  </g>
  <circle r="6" style={{ fill: "var(--ngc-green)" }}><animate attributeName="cx" values="470;560" dur="2.4s" repeatCount="indefinite" /><animate attributeName="cy" values="55;42" dur="2.4s" repeatCount="indefinite" /></circle>
  <circle r="6" style={{ fill: "var(--ngc-green)" }}><animate attributeName="cx" values="470;560" dur="2.4s" begin="0.8s" repeatCount="indefinite" /><animate attributeName="cy" values="97;98" dur="2.4s" begin="0.8s" repeatCount="indefinite" /></circle>
  <circle r="6" style={{ fill: "var(--ngc-green)" }}><animate attributeName="cx" values="470;560" dur="2.4s" begin="1.6s" repeatCount="indefinite" /><animate attributeName="cy" values="139;154" dur="2.4s" begin="1.6s" repeatCount="indefinite" /></circle>
  <rect x="190" y="160" width="120" height="30" rx="15" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-green)", strokeWidth: 1.5 }} />
  <text x="250" y="180" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>JavaScript: 0 KB</text>
</svg>
<figcaption>Astro makes the HTML once, at build time. Every visitor gets the same finished page.</figcaption>
</figure>

**Build time** = the moment Astro turns your files into finished pages, before anyone visits. In this course, "build" always means this step.

**Simple lesson:** Astro does the work before the visitor arrives, so the visitor's browser has less to do.

## Why Astro Was Created

- Many sites, like blogs and docs, are mostly text and pictures.
- Tools made for apps often send these sites a lot of JavaScript anyway.
- The phone must download and run that JavaScript before the page works.
- On a cheap phone or a slow network, this makes the page feel slow.
- Astro was made for these content sites. Version 1.0 came out in 2022.
- Its idea is simple: send HTML, and send JavaScript only where it is needed.

### Features of Astro

- **Content-driven.** Made for sites full of text, images and posts. It has built-in tools for Markdown and blog posts.
- **Server-first.** Pages are made into HTML before they reach the visitor. The visitor's browser does not build them. This is why they load fast.
- **Zero JavaScript by default.** A page ships no JavaScript unless you add some. Less to download means a faster page.
- **UI-agnostic.** You can use React, Vue, Svelte or other UI tools inside Astro. You are not locked to one.
- **Fast by default.** You get a fast site without extra work. The features above do the work for you.

**UI-agnostic** = Astro does not care which UI tool you use. "Agnostic" here means "does not pick a side".

**Simple lesson:** Astro was made for content sites, so its default choices make content sites fast.

## The Astro Approach

### JavaScript Only Where Needed

- Most of a page never changes after it loads: headings, text, pictures, links.
- Only a few parts react to the visitor: a menu button, a like button, a search box.
- Astro sends plain HTML for the parts that never change.
- It adds JavaScript only for the parts that react.
- Astro calls these small interactive parts **islands**. You will learn them in **Astro Islands**.

Watch the animation. The page is a sea of plain HTML. Only the like button needs JavaScript.

<figure className="ast-fig ngc-fig">
<svg viewBox="0 0 640 230" role="img" aria-labelledby="fig-astro-island" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-astro-island">Animation: a web page with a header, text and an image in plain HTML, and one like button that glows because it is the only part with JavaScript.</title>
  <rect x="20" y="16" width="380" height="200" rx="12" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
  <rect x="20" y="16" width="380" height="24" rx="12" style={{ fill: "var(--ngc-winbar)" }} />
  <text x="210" y="33" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--sans)", fontSize: 12 }}>A blog post page</text>
  <g style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)" }}>
    <rect x="36" y="52" width="348" height="26" rx="6" />
    <rect x="36" y="88" width="210" height="92" rx="6" />
    <rect x="256" y="88" width="128" height="60" rx="6" />
  </g>
  <g style={{ fill: "var(--ngc-blue)", fontFamily: "var(--sans)", fontSize: 12, fontWeight: 700 }}>
    <text x="210" y="70" textAnchor="middle">Header (HTML)</text>
    <text x="141" y="138" textAnchor="middle">Post text (HTML)</text>
    <text x="320" y="122" textAnchor="middle">Image (HTML)</text>
  </g>
  <rect x="256" y="156" width="128" height="40" rx="8" style={{ fill: "var(--ngc-orange)", stroke: "var(--ngc-orange)" }}>
    <animate attributeName="opacity" values="1;0.55;1" dur="1.6s" repeatCount="indefinite" />
  </rect>
  <text x="320" y="181" textAnchor="middle" style={{ fill: "#fff", fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>♥ Like (JS)</text>
  <g style={{ fontFamily: "var(--sans)", fontSize: 13 }}>
    <rect x="430" y="60" width="16" height="16" rx="3" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)" }} />
    <text x="454" y="73" style={{ fill: "var(--ink2)" }}>Plain HTML: no JavaScript</text>
    <rect x="430" y="96" width="16" height="16" rx="3" style={{ fill: "var(--ngc-orange)" }} />
    <text x="454" y="109" style={{ fill: "var(--ink2)" }}>Island: has JavaScript</text>
    <text x="430" y="150" style={{ fill: "var(--ngc-slate)", fontWeight: 700 }}>Most of the page: HTML</text>
    <text x="430" y="172" style={{ fill: "var(--ngc-orange)", fontWeight: 700 }}>One small part: JavaScript</text>
  </g>
</svg>
<figcaption>Only the part that reacts to clicks gets JavaScript.</figcaption>
</figure>

### See It in Code

- The lab below has a page with one button.
- The heading and the list are plain HTML.
- Only the `<script>` tag adds JavaScript, for the button.

Press **▶ Run** and click the button. Then open **HTML sent to browser** and find the one `<script>` tag.

<ul>
    {topics.map((topic) => <li>{topic}</li>)}
</ul>

<button id="like">♥ Like (0)</button>

<script>
    const button = document.getElementById("like");
    let likes = 0;
    button?.addEventListener("click", () => {
      likes = likes + 1;
      button.textContent = "♥ Like (" + likes + ")";
    });
</script>
`,
  }}
/>

What to compare:

- **The list:** it arrives as three finished `<li>` tags. The browser runs nothing to make it.
- **The button:** it needs the small `<script>` to count clicks.
- **The size:** the JavaScript is a few lines, not a whole framework.

**Simple lesson:** in Astro, JavaScript is something you add on purpose, only to the parts that react.

## What You Can Build with Astro

Astro is a very good fit for:

- Blogs and personal sites.
- Documentation sites.
- Marketing and landing pages.
- Portfolios.
- Online shop pages, such as product lists and product pages.
- News and magazine sites.

Astro is a weaker fit for:

- Apps where almost every part reacts all the time. Examples: a photo editor or a chat app.
- Apps that work like a game, with the screen changing every second.

For those, a tool built for apps, such as React or Next.js, is often easier.

**Simple lesson:** the more your site is "read and look", the better Astro fits.

## Astro Compared to Other Tools

### Astro vs React

- **React** = a JavaScript library for building interactive user interfaces.
- React builds the page in the browser by default, with JavaScript.
- Astro builds the page into HTML before the visit.
- They are not rivals. You can use React components inside an Astro page.

### Astro vs Next.js

- **Next.js** = a framework built on React for building full web apps.
- Next.js is made for apps first. Every page is a React app.
- Astro is made for content first. A page is HTML unless you add an island.
- Both can make pages ahead of time and on a server.

### When to Choose Astro

<div className="tscroll">

| Question | Astro | Next.js | React (on its own) |
|---|---|---|---|
| Main job | Content sites | Full web apps | Interactive screens |
| JavaScript sent by default | None | React and your page code | All of the app |
| Best for | Blogs, docs, marketing pages | Dashboards, shops with many features | Single-page apps |
| Can use other UI tools | Yes: React, Vue, Svelte and more | React only | React only |
| How fast the first view shows | Very fast | Fast | Slower, it waits for JavaScript |

</div>

**Simple lesson:** pick Astro when your site is mostly content. Pick an app framework when your site is mostly interaction.

## The Astro Ecosystem

- **Ecosystem** = the tools, add-ons and help that grow around a framework.
- **Themes and starter templates** = ready-made Astro sites you can copy and change. The Astro website lists many of them.
- **Starlight** = an official Astro tool for building documentation sites. It gives you search, a sidebar and dark mode.
- **Integrations** = add-ons you plug into Astro, such as React, Tailwind CSS or a sitemap. You will add one in **Project Structure and Configuration**.
- **Astro docs** = the official guide at docs.astro.build. It has a free step-by-step tutorial that builds a blog.

Keep the Astro docs open while you learn. When this course says "real Astro does X", the docs are where you can check it.

**Simple lesson:** you rarely start from zero. Use a starter, a theme or Starlight, then change it.

## Astro Versions and Release Cycle

- This course uses **Astro 7**, the current major version. It came out in 2026.
- A **major version** (5, 6, 7) can change or remove old features.
- A **minor version** (7.1, 7.2) adds features without breaking your code.
- A **patch version** (7.4.11) fixes bugs.
- Astro usually ships one new major version each year, and new minor versions every few weeks.

When you read an old blog post, check the version. Some old code no longer works in Astro 7. For example:

- `Astro.glob()` was removed. You will learn its replacement in **Markdown and MDX**.
- `output: "hybrid"` was removed. You will learn why in **How Astro Renders Pages**.

**Simple lesson:** check the Astro version before you copy code from the internet.

## Before You Start: System Requirements

You need three things on your computer.

### Node.js

- **Node.js** = a program that runs JavaScript outside the browser. Astro's tools run on it.
- Astro 7.4 needs Node.js **22.23.4 or newer**.
- Use an **even-numbered** LTS release, such as 22 or 24. LTS means "long-term support".
- The Astro docs say odd-numbered releases, such as 23 or 25, are not supported.
- Download it from nodejs.org. The installer also installs **npm**, the tool that downloads packages.

Check it in a terminal:

```bash
node -v
```

- It prints a version such as `v24.11.0`.
- If it prints an error, or a version below 22.23.4, install the newest LTS version.

### A Code Editor

- **VS Code** is free and the most common choice.
- Install the official **Astro** extension. It colours `.astro` files and suggests code as you type.

### A Terminal

- **Terminal** = a window where you type commands.
- On Windows, use **PowerShell** or the terminal inside VS Code.
- On a Mac or Linux, use the **Terminal** app.

**Simple lesson:** Node.js, an editor and a terminal are all you need. All three are free.

## Creating an Astro Project

### The Setup Wizard

- Run `npm create astro@latest` in a terminal.
- It starts a **setup wizard**: a few questions with good default answers.
- It asks four things:
  - where to create the project,
  - which starter template to use,
  - whether to install the packages,
  - whether to start a Git repository.
- Press Enter to accept each default.

Click **Next** to see each command and what it prints.

### Choosing a Starter Template

The wizard offers these starters:

- **A basic, helpful starter project** (recommended): one page with a little styling.
- **Use blog template**: a ready blog with posts.
- **Use docs (Starlight) template**: a ready documentation site.
- **Use minimal (empty) template**: one empty page. Good for learning.

### TypeScript and JavaScript

- **TypeScript** = JavaScript with types. Types tell your editor what kind of value a name holds.
- The Astro 7 wizard does not ask about TypeScript any more.
- Every new project gets a `tsconfig.json` with Astro's **strict** settings.
- **If you write TypeScript:** you are ready. Write types in your `.astro` and `.ts` files.
- **If you write JavaScript:** you are ready too. Write plain JavaScript and `.js` files. `tsconfig.json` still gives your editor hints.
- Pick your flavour with the **TypeScript / JavaScript** switch in the top bar. Every lab on this site follows it.

### Useful Flags

- **Flag** = an extra word after a command that changes what it does. It starts with `--`.

```bash
npm create astro@latest -- --template minimal
npm create astro@latest -- --template blog --add react
```

- `--template` picks a starter without asking.
- `--add` adds an integration, such as React, while creating the project.
- The first `--` tells npm to pass the flags on to the wizard.

### Using pnpm, Yarn or Bun

npm is not the only package manager. These commands do the same job:

```bash
pnpm create astro@latest
yarn create astro
bun create astro@latest
```

- Use the one your team already uses.
- This course uses npm.

### Manual Installation

- You can also set up a project by hand: make a folder, run `npm install astro`, and add `src/pages/index.astro`.
- The wizard does all of this for you, so most people use it.

**Simple lesson:** run `npm create astro@latest`, accept the defaults, and you have a working site.

## Project Structure

A new project has a few files and folders. Click each one to see its job.

The most important rule:

- **Every `.astro` file in `src/pages/` becomes a page of your site.**
- `src/pages/index.astro` becomes `/` (the home page).
- `src/pages/about.astro` becomes `/about`.

You will meet every file in detail in **Project Structure and Configuration**.

### Try It: Add a Second Page

- The lab has two pages: `index.astro` and `about.astro`.
- Press **▶ Run**, then click the **About** link in the preview.
- The address bar changes to `/about`. You can also pick a page from the address bar.

<p>I write about what I learn.</p>
<a href="/about">About</a>
`,
    "src/pages/about.astro": `---
const city: string = "Chennai";
---

<h1>About Me</h1>
<p>I am a student from {city}.</p>
<a href="/">Home</a>
`,
  }}
/>

**Simple lesson:** to add a page, add a file to `src/pages`.

## Running the Project

### The Dev Server

- Run `npm run dev` inside your project folder. It runs `astro dev`.
- **Dev server** = a small test website that runs on your own computer.
- Open **http://localhost:4321** to see your site. **4321** is Astro's default port.
- **Port** = a numbered door on your computer that a program listens on.
- Press **Ctrl+C** in the terminal to stop it.

### Hot Reloading

- **Hot reloading** = the browser updates by itself when you save a file.
- You do not need to press refresh.
- Edit a file, save it, and look at the browser. The change is already there.

### Changing the Port

If another program already uses port 4321, start Astro on another port:

```bash
npm run dev -- --port 3000
```

### Build and Preview

- `npm run build` runs `astro build`. It makes the finished site in the `dist/` folder.
- `npm run preview` runs `astro preview`. It shows the `dist/` folder, so you can check the real result.
- You upload the `dist/` folder to a web host. You will do this in **Deploying Your Site**.

<figure className="ast-fig ngc-fig">
<svg viewBox="0 0 640 170" role="img" aria-labelledby="fig-astro-cli" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-astro-cli">Animation: the three commands in order. astro dev for writing code, astro build to make the dist folder, astro preview to check it before you publish.</title>
  <defs><marker id="ac-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0 L10 5 L0 10 z" style={{ fill: "var(--ngc-slate)" }} /></marker></defs>
  <g style={{ fontFamily: "var(--mono)", fontWeight: 700, fontSize: 15 }}>
    <rect x="20" y="40" width="170" height="60" rx="12" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)", strokeWidth: 1.5 }}><animate attributeName="stroke-width" values="4;1.5;1.5;4" keyTimes="0;0.33;0.99;1" dur="6s" repeatCount="indefinite" /></rect>
    <text x="105" y="76" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>astro dev</text>
    <rect x="235" y="40" width="170" height="60" rx="12" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 1.5 }}><animate attributeName="stroke-width" values="1.5;1.5;4;1.5;1.5" keyTimes="0;0.33;0.34;0.66;1" dur="6s" repeatCount="indefinite" /></rect>
    <text x="320" y="76" textAnchor="middle" style={{ fill: "var(--ngc-orange)" }}>astro build</text>
    <rect x="450" y="40" width="170" height="60" rx="12" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 1.5 }}><animate attributeName="stroke-width" values="1.5;1.5;4;1.5" keyTimes="0;0.66;0.67;1" dur="6s" repeatCount="indefinite" /></rect>
    <text x="535" y="76" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>astro preview</text>
  </g>
  <path d="M190 70 H231" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#ac-arrow)" />
  <path d="M405 70 H446" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#ac-arrow)" />
  <g style={{ fontFamily: "var(--sans)", fontSize: 12.5, fill: "var(--ink2)" }}>
    <text x="105" y="124" textAnchor="middle">While you write code</text>
    <text x="105" y="142" textAnchor="middle">Updates on every save</text>
    <text x="320" y="124" textAnchor="middle">When you are done</text>
    <text x="320" y="142" textAnchor="middle">Makes the dist/ folder</text>
    <text x="535" y="124" textAnchor="middle">Before you publish</text>
    <text x="535" y="142" textAnchor="middle">Shows the dist/ folder</text>
  </g>
</svg>
<figcaption>Write with dev. Finish with build. Check with preview.</figcaption>
</figure>

### Where Your Code Runs

- The **component script** (between the `---` lines) runs on your computer when the page is built.
- Its `console.log` prints in the **terminal**, not in the browser.
- A `<script>` tag runs later, in the visitor's **browser**.
- Its `console.log` prints in the browser's console.

Press **▶ Run**. The **Terminal** view tags each line with where it ran. Then click the button.

<button id="hello">Say hello</button>

<script>
    // Runs in the visitor's browser.
    console.log("The page has loaded in the browser");
    document.getElementById("hello")?.addEventListener("click", () => {
      console.log("Hello from the browser!");
    });
</script>
`,
  }}
/>

What to compare:

- **[terminal] lines:** printed while Astro built the page.
- **[browser] lines:** printed by the `<script>` in the visitor's browser.
- **On your own computer:** the first line appears in the terminal that runs `npm run dev`. The others appear in the browser's developer tools.

Never put a secret, such as a password or an API key, in a `<script>` tag. Everything in a `<script>` is sent to every visitor.

**Simple lesson:** the component script runs at build time. The `<script>` tag runs in the browser.

## The Astro CLI

- **CLI** = command-line interface: a tool you use by typing commands.
- `astro` is Astro's CLI. `npm run dev` is a short way to call `astro dev`.

Two commands help you when you are stuck:

```bash
npx astro --help
npx astro info
```

- `astro --help` lists every command and what it does.
- `astro info` prints your Astro, Node.js and system versions. Paste it when you ask for help online.

### A Starter Page in the Lab

This is close to the `src/pages/index.astro` file of the **minimal** starter. Change the heading, then press **▶ Run**.

    <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>
      <h1>Astro</h1>
    </body>
</html>
`,
  }}
/>

- The two `---` lines are there, even with nothing between them.
- `Astro.generator` adds the Astro version to the page. Look for `content="Astro v7` in **HTML sent to browser**.

**Simple lesson:** `astro --help` and `astro info` are your first two helpers.

## TL;DR

1. **Astro** = a web framework for fast, content-driven websites.
2. **HTML first** = Astro makes finished HTML before anyone visits.
3. **Zero JavaScript by default** = a page sends no JavaScript unless you add some.
4. **Island** = a small part of a page that has JavaScript.
5. **Choose Astro** = when your site is mostly content. Choose an app framework when it is mostly interaction.
6. **Requirements** = Node.js 22.23.4 or newer (even-numbered LTS), an editor, a terminal.
7. **Project steps:**
   - `npm create astro@latest` creates the project.
   - `npm run dev` starts the dev server at localhost:4321.
   - `npm run build` makes the `dist/` folder.
   - `npm run preview` shows the built site.
8. **src/pages** = every `.astro` file here becomes a page.
9. **Component script** = the code between `---` lines. It runs at build time.

## Common mistakes

<div className="tscroll">

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Using Node.js 23 or an old version | Any Node.js works | Use an even-numbered LTS, 22.23.4 or newer | Astro stops with "Node.js is not supported" |
| Running commands outside the project | The terminal knows where the project is | `cd` into the project folder first | npm says it cannot find `package.json` |
| Putting a page outside `src/pages` | Any `.astro` file is a page | Only files in `src/pages` become pages | The address shows a 404 page |
| Code above the first `---` | The script can go anywhere | Put the script between the two `---` lines | The code shows as text, or the build fails |
| Uploading the project folder | The source files are the website | Run `npm run build` and upload `dist/` | The host shows files, not a website |
| Looking for a frontmatter `console.log` in the browser | All code runs in the browser | The component script runs at build time | You see nothing in the browser console |
| Copying old Astro code | All Astro code online is the same | Check the version first | Removed features, such as `Astro.glob()`, fail |

</div>

## Check Yourself

## Exercises

## What to Remember

- Astro builds content sites into fast, finished HTML.
- It sends JavaScript only for the parts that react.
- Pick Astro for content. Pick an app framework for heavy interaction.
- `npm create astro@latest`, then `npm run dev`, `npm run build` and `npm run preview`.
- Every `.astro` file in `src/pages` becomes a page.
- The component script runs at build time. A `<script>` tag runs in the browser.

Next: **Project Structure and Configuration**, where you meet every file of a project and add your first integration.
