src/pages/)This directory contains all routes using Astro’s file-based routing system. Each .astro or .ts file becomes a route based on its file path.
pages/
├── index.astro # Homepage (/)
├── about.astro # About page (/about)
├── contact.astro # Contact page (/contact)
├── rss.xml.js # RSS feed (/rss.xml)
├── api/
│ └── posts.json.ts # Blog search API (/api/posts.json)
├── blog/
│ ├── index.astro # Blog listing (/blog)
│ ├── [...slug].astro # Individual posts (/blog/{slug})
│ ├── page/
│ │ └── [page].astro # Blog pagination (/blog/page/{n})
│ └── tag/
│ ├── [tag].astro # Tag page (/blog/tag/{tag})
│ └── [tag]/
│ └── page/
│ └── [page].astro # Tag pagination (/blog/tag/{tag}/page/{n})
└── es/
└── index.astro # Spanish homepage (/es)
| File | Route | Description |
|---|---|---|
index.astro | / | English homepage |
about.astro | /about | About page |
contact.astro | /contact | Contact page |
rss.xml.js | /rss.xml | RSS feed |
api/posts.json.ts | /api/posts.json | Blog search API |
blog/index.astro | /blog | Blog listing (page 1) |
blog/[...slug].astro | /blog/{slug} | Individual blog post |
blog/page/[page].astro | /blog/page/{n} | Blog pagination |
blog/tag/[tag].astro | /blog/tag/{tag} | Posts by tag (page 1) |
blog/tag/[tag]/page/[page].astro | /blog/tag/{tag}/page/{n} | Tag pagination |
es/index.astro | /es | Spanish homepage |
Files without brackets become static routes:
pages/about.astro → /about
pages/contact.astro → /contact
Files with brackets ([]) become dynamic routes:
pages/blog/[...slug].astro → /blog/any-slug-here
pages/blog/page/[page].astro → /blog/page/2
pages/blog/tag/[tag].astro → /blog/tag/tech
The [...slug] syntax captures all segments:
pages/blog/[...slug].astro
→ /blog/my-post-slug
→ /blog/nested/path/here
---
import MainLayout from '@/layouts/MainLayout.astro';
const lang = 'en';
---
<MainLayout lang={lang} title="Page Title" description="Page description">
<main class="main-container py-24">
<!-- Content -->
</main>
</MainLayout>
getStaticPathsFor dynamic routes, you must export getStaticPaths:
---
import { getCollection } from 'astro:content';
import MainLayout from '@/layouts/MainLayout.astro';
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map(post => ({
params: { slug: post.id },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = await post.render();
---
<MainLayout title={post.data.title}>
<Content />
</MainLayout>
---
import { getCollection } from 'astro:content';
import { BLOG_PAGE_SIZE } from '@/lib/constances';
export async function getStaticPaths() {
const posts = await getCollection('blog');
const totalPages = Math.ceil(posts.length / BLOG_PAGE_SIZE);
return Array.from({ length: totalPages }, (_, i) => ({
params: { page: String(i + 1) },
props: {
posts: posts.slice(i * BLOG_PAGE_SIZE, (i + 1) * BLOG_PAGE_SIZE),
currentPage: i + 1,
totalPages,
},
}));
}
const { posts, currentPage, totalPages } = Astro.props;
---
API routes use .ts files and export HTTP method handlers:
// pages/api/posts.json.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
const data = await fetchData();
return new Response(JSON.stringify(data), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
};
| Endpoint | Method | Description |
|---|---|---|
/api/posts.json | GET | Blog posts search index |
See API Reference for details.
The RSS feed is generated at build time:
// pages/rss.xml.js
import rss from '@astrojs/rss';
import { getCollection } from 'astro:content';
export async function GET(context) {
const posts = await getCollection('blog');
return rss({
title: 'My Blog',
description: 'Blog description',
site: context.site,
items: posts.map(post => ({
title: post.data.title,
pubDate: post.data.pubDate,
link: `/blog/${post.id}/`,
})),
});
}
Currently using folder-based i18n:
/ (root)/es/See i18n Guide for details.
Create file in pages/:
touch src/pages/new-page.astro
Add content:
---
import MainLayout from '@/layouts/MainLayout.astro';
---
<MainLayout lang="en" title="New Page" description="Description">
<main class="main-container py-24">
<h1>New Page</h1>
</main>
</MainLayout>
Create file with brackets:
touch src/pages/items/[id].astro
Export getStaticPaths:
---
export async function getStaticPaths() {
const items = await getItems();
return items.map(item => ({
params: { id: item.id },
props: { item },
}));
}
const { item } = Astro.props;
---
Create .ts file:
touch src/pages/api/data.json.ts
Export handler:
import type { APIRoute } from 'astro';
export const GET: APIRoute = async () => {
return new Response(JSON.stringify({ data: [] }), {
headers: { 'Content-Type': 'application/json' },
});
};