---
title: "Astro — Markdown Mirrors"
description: "Astro's content collections make .md mirrors trivial."
type: "page"
canonical: "https://audigeo.ai/docs/integrations/markdown-mirrors/astro"
---

# Astro — Markdown Mirrors

Astro stores content as `.md` natively. Two patterns:

## 1. Direct file serving

If your content collection lives at `src/content/pages/`, expose it via a dynamic route:

`src/pages/[...slug].md.ts`:

```ts
import type { APIRoute } from "astro";
import { getCollection } from "astro:content";

export async function getStaticPaths() {
  const pages = await getCollection("pages");
  return pages.map((page) => ({ params: { slug: page.slug }, props: { page } }));
}

export const GET: APIRoute = async ({ props }) => {
  const { page } = props as any;
  const fm = `---
title: ${JSON.stringify(page.data.title)}
description: ${JSON.stringify(page.data.description ?? "")}
type: "page"
canonical: "https://example.com/${page.slug}"
---

`;
  return new Response(fm + page.body, {
    headers: {
      "Content-Type": "text/markdown; charset=utf-8",
      "Cache-Control": "public, max-age=3600",
      "X-Robots-Tag": "index, follow",
    },
  });
};
```

## 2. llms-full.txt

`src/pages/llms-full.txt.ts`:

```ts
import type { APIRoute } from "astro";
import { getCollection } from "astro:content";

export const GET: APIRoute = async () => {
  const pages = await getCollection("pages");
  const lines = ["# My Site — LLM-friendly index", ""];
  for (const p of pages) {
    lines.push(`- https://example.com/${p.slug}.md`);
  }
  return new Response(lines.join("\n"), {
    headers: { "Content-Type": "text/plain; charset=utf-8" },
  });
};
```

## Verify

Run an AudiGEO audit. Target: `markdown_mirror` ≥ 7.
