Project & .astro Files
The project layout
Section titled “The project layout”A typical Astro project has a small, conventional structure:
my-site/├── astro.config.mjs # config: integrations, adapter, output mode├── src/│ ├── pages/ # file-based routing — each file is a route│ ├── components/ # reusable .astro (and framework) components│ ├── layouts/ # shared page shells│ ├── content.config.ts # content collections config (Astro 5+)│ └── styles/└── public/ # static assets served as-is (favicon, robots.txt)Two folders are load-bearing:
src/pages/is file-based routing:src/pages/index.astro→/,src/pages/about.astro→/about,src/pages/blog/[slug].astro→/blog/:slug. The file’s location is the route.public/is copied to the output verbatim — files here are served at the root, unprocessed.
Anatomy of a .astro file
Section titled “Anatomy of a .astro file”The .astro file is Astro’s own component format. It has two parts separated by a code fence (---):
---// 1. The component script (frontmatter). Runs on the SERVER only.// JavaScript/TypeScript here: imports, data fetching, props, logic.import Card from '../components/Card.astro';
const title = "Latest posts";const posts = await fetch('https://api.example.com/posts').then((r) => r.json());---
<!-- 2. The template. Becomes HTML. Uses { } to embed JS expressions. --><h1>{title}</h1><ul> {posts.map((post) => <Card title={post.title} />)}</ul>The key mental model:
- Everything above the second
---is the component script — it runs once, on the server, at build time (or per request for on-demand pages). This is where you fetch data, import components, and compute values. None of it ships to the browser. - Everything below is the template — HTML with
{ }expressions that drop into JavaScript. This is what becomes the rendered HTML.
flowchart LR
script["--- frontmatter ---
component script
(server only)"] --> compute["fetch data, compute props"]
compute --> template["template (HTML + { } expressions)"]
template --> html["rendered HTML"] Because the script runs on the server, you can await at the top level — fetch from an API or database directly in a component, with no useEffect, no loading state, no client round-trip. The data is already there when the HTML is built.
It’s a superset of HTML
Section titled “It’s a superset of HTML”An .astro template is valid HTML plus JSX-like expressions. If you paste plain HTML into a .astro file, it just works. You add dynamism with { } (expressions), {condition && <div/>} (conditionals), and {items.map(...)} (loops) — the same expression syntax you saw in the landing example. Unlike JSX, you use standard HTML attribute names (class, not className).