Astro
02 / 02

Routing, Rendering Modes & Content Collections

Astro: Routing, Rendering Modes & Content Collections

Static (SSG) vs Server (SSR) Rendering

// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
import react from '@astrojs/react';
import tailwind from '@astrojs/tailwind';

export default defineConfig({
  output: 'server',       // default is 'static' -- most content doesn't need per-request rendering
  adapter: vercel(),       // SSR requires a deployment adapter
  integrations: [react(), tailwind()],
});
---
// Per-route override: mix static and server-rendered pages in one project.
// A static marketing homepage alongside a personalized, server-rendered dashboard.
export const prerender = false;   // this specific route renders per-request

const user = await getSessionUser(Astro.request);
---

<h1>Welcome back, {user.name}</h1>

Dynamic Routes

---
// src/pages/blog/[slug].astro
// getStaticPaths declares, at build time, every concrete path to
// pre-render for this dynamic route -- one page per blog post
export async function getStaticPaths() {
  const posts = await getAllPosts();
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
---

<h1>{post.title}</h1>
<div set:html={post.contentHtml} />

Content Collections

// src/content/config.ts -- type-safe schema for Markdown/MDX content
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  type: 'content',
  schema: z.object({
    title: z.string(),
    publishDate: z.date(),
    tags: z.array(z.string()).default([]),
    draft: z.boolean().default(false),
  }),
});

export const collections = { blog };

// A post's frontmatter is now validated at BUILD TIME -- a missing
// publishDate or a wrong type fails the build instead of shipping broken data

// src/pages/blog/[...slug].astro
---
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('blog');
  return posts.map((post) => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await post.render();
---

<h1>{post.data.title}</h1>
<Content />

Image Optimization

---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---

<!-- Auto-optimized at build time: resized, format-converted (e.g. WebP),
     width/height set automatically to prevent layout shift -->
<Image src={heroImage} alt="Hero" width={800} height={400} />

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free