Skip to content

Pages and sections

A page is a small .astro file in src/pages/ that picks sections and hands them content. The file’s path is its URL: src/pages/about.astro is /about. The whole About page:

---
import AboutHeroSection from "../components/sections/AboutHeroSection.astro";
import ValuesSection from "../components/sections/ValuesSection.astro";
import about from "../content/pages/about.json";
import Layout from "../layouts/Layout.astro";
---
<Layout title={about.meta.title} description={about.meta.description}>
<AboutHeroSection content={about.hero} />
<ValuesSection intro={about.values.intro} values={about.values.items} />
</Layout>

Layout writes the <head> (title, description, canonical link, share card), the header, the footer and the cursor.

In src/components/sections/. Each takes its copy as content and its data as a list.

Section Used on
HomeHeroSection, AboutSection, ServicesSection, ProjectsSection, TestimonialsSection, BlogSection, CtaSection Home
AboutHeroSection, ValuesSection, PageImageSection, TeamSection About
ServiceCatalogSection, ServiceHeroSection, ServiceContentSection, MoreServicesSection Services
ProjectGallerySection, ProjectHeroSection, ProjectContentSection, NextProjectSection Projects
BlogArchiveSection, PostHeroSection, PostContentSection, MoreBlogSection Blog
CareerCatalogSection, CareerDetailSection, MoreOpeningsSection Careers
ContactSection Contact
NotFoundSection 404

Move the lines in the page file, or delete one. To take the testimonials off the home page, delete <TestimonialsSection … /> from src/pages/index.astro; its copy in src/content/pages/home.json can stay or go.

  1. Add its copy to src/content/pages/pricing.json, with a meta (title, description).
  2. Create src/pages/pricing.astro:
    ---
    import CtaSection from "../components/sections/CtaSection.astro";
    import pricing from "../content/pages/pricing.json";
    import Layout from "../layouts/Layout.astro";
    ---
    <Layout title={pricing.meta.title} description={pricing.meta.description}>
    <CtaSection content={pricing.cta} />
    </Layout>
  3. Add the URL to src/content/routes.ts (pricing: "/pricing") if components link to it.
  4. Link to it: add { "label": "Pricing", "href": "/pricing" } to navigation in src/content/site.json, or to the footer links.
  5. Add it to src/pages/sitemap.xml.ts, next to the other top-level pages.

Delete its file in src/pages/, its entry in navigation and in sitemap.xml.ts, and the route in routes.ts. npm run check and npm run build then tell you about anything still pointing at it.

src/pages/blog/[slug].astro builds one page per post:

export const getStaticPaths = (async () => {
const posts = await getPosts();
return posts.map((post) => ({ params: { slug: post.slug }, props: { post, posts } }));
}) satisfies GetStaticPaths;

Add a post to src/content/collections/posts.json and its page, its links and its sitemap entry appear on the next build. Any slug not in the list is a 404. The project, service and career pages work the same way.

src/pages/404.astro, with its copy in src/content/pages/not-found.json. It is noindex, like the style guide. Most hosts serve 404.html automatically for unknown URLs.

  • src/pages/sitemap.xml.ts builds sitemap.xml from routes.ts and the collections, so new items list themselves.
  • src/pages/robots.txt.ts builds robots.txt and points at the sitemap. Both use site.url, so set your domain before publishing.
  • Every indexable page gets a canonical link and an og:url from Layout.astro. Pass noindex to Layout to keep a page out of search results.