Data, content, and assets

Query and render a collection

Load entries, filter drafts, sort dates, and pass one consistent content shape into the page.

Once a collection is defined, pages query it with getCollection() from astro:content. The function returns an array of entries, and each entry carries an id plus its frontmatter under data.

Here is a listing page:

---
import { getCollection } from "astro:content"

const notes = await getCollection("notes", ({ data }) => !data.draft)

notes.sort(
  (a, b) => b.data.publishedAt.valueOf() - a.data.publishedAt.valueOf()
)
---

<ul>
  {notes.map(note => (
    <li><a href={`/notes/${note.id}/`}>{note.data.title}</a></li>
  ))}
</ul>

The second argument is a filter callback. Every entry it rejects disappears from the result, so drafts never produce a link here. Filter drafts before creating links or routes, not after, so unpublished URLs are not accidentally generated anywhere.

Do not rely on the loader’s entry order; it reflects how files were read, not any publishing policy. Sort explicitly where the listing policy belongs, as the publishedAt comparison above does.

For a detail route, select the entry in getStaticPaths() and render its body:

---
import { getCollection, render } from "astro:content"

export async function getStaticPaths() {
  const notes = await getCollection("notes", ({ data }) => !data.draft)
  return notes.map(note => ({ params: { id: note.id }, props: { note } }))
}

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

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

render() compiles the entry’s Markdown and hands back a <Content /> component you place in the template like any other component. Each generated page receives its own entry through props, so the detail route never re-queries the whole collection at render time.

Keep selection and sorting near the route. Presentational components should receive a small, consistent shape instead of knowing how the entire collection is stored.

A mistake worth recognizing: forgetting await in front of getCollection(). You get a Promise instead of an array, and the first symptom is usually notes.sort is not a function or an empty listing. Check the query line before suspecting the collection itself.

Build the site and count the generated note pages under dist/notes/. The number should match the entries that pass the draft filter, not the total files in the collection.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →