---
title: "Read and list pages"
description: "Read one page with get() and every page with list(), with the inputs and outputs of each."
canonical_url: "https://content.comark.dev/guide/read-and-list"
---
# Read and list pages

> Read one page with get() and every page with list(), with the inputs and outputs of each.

Two methods cover most of what an app does with content. [`get()`](#read-one-page) reads one page, body included. [`list()`](#list-pages) returns every page's frontmatter without parsing any body. Both work on the same instance:

```
content/
  index.md
  about.md
  blog/
    hello.md
    second-post.md
```

```ts [content.ts]
import { comarkContent } from 'comark-content'
import fs from 'comark-content/sources/fs'

export const content = comarkContent({
  source: fs('./content'),
})
```

## Read one page

Pass a public path to `get()`. It returns the page with its parsed body:

```ts
const page = await content.get('/blog/hello') // reads ./content/blog/hello.md

if (!page) {
  // no file maps to /blog/hello
}

page.path // '/blog/hello'
page.data.title // from the frontmatter
page.nodes // parsed body, for a renderer
```

The result is `null` when no page has that path, so check it before you render. In a web framework, that check is usually a 404:

```ts
const page = await content.get(`/blog/${slug}`)
if (!page) notFound()
```

The first `get()` of a path reads the file and parses the body. The result stays in memory, so later reads of the same path in the same process don't parse again. When you edit a file while your server runs, the instance needs to be told; [Watch content changes](https://content.comark.dev/guide/watch) covers that.

::note
`get()` also accepts the file's key, such as `blog/hello.md`, and it returns `undefined` for a path that exists but isn't a document, such as an image. See the [`content.get()` reference](https://content.comark.dev/reference/content/get) for those cases and the `fresh` option.
::

## List pages

`list()` returns one entry per page, with everything except `nodes`:

```ts
const pages = await content.list()

pages.map((page) => page.path)
// ['/', '/about', '/blog/hello', '/blog/second-post']

pages[0].data.title // the frontmatter, same as get()
pages[0].nodes // does not exist on a list entry
```

Listing reads only the frontmatter of each file, so it stays cheap as your content grows. Filter and sort the array with ordinary JavaScript:

```ts
const posts = (await content.list())
  .filter((page) => page.path.startsWith('/blog/'))
  .filter((page) => !page.data.draft)
  .sort((a, b) => String(b.data.date).localeCompare(String(a.data.date)))
```

Frontmatter fields you filter or sort on, like `draft` and `date`, belong in the frontmatter for this reason: they're available to `list()` without a body parse.

When frontmatter is large and listings only need a few fields, [`addListingFields()`](https://content.comark.dev/reference/content/add-listing-fields) trims what `list()` keeps.

## Build pages from a list

A common pattern combines the two: list once to know which pages exist, then `get()` each one when it's rendered. In a framework with static generation, the list feeds the route list:

```ts
// Which routes to generate
const pages = await content.list()
const routes = pages.map((page) => page.path)

// What to render for one of them
const page = await content.get(route)
```

The [framework guides](https://content.comark.dev/getting-started/render-your-first-page) show this with each framework's own API.

## Beyond get and list

- **[`navigation()`](https://content.comark.dev/guide/navigation)** turns the list into a tree that mirrors your folders, ready for a sidebar.
- **Filtered, paginated queries** over frontmatter, in SQL, come with the [`sqlQuery` plugin](https://content.comark.dev/plugins/built-in/sql-query).
- **Full-text search** over bodies, with ranked results and highlighted snippets, comes with the [`sqliteFullTextSearch` plugin](https://content.comark.dev/plugins/built-in/full-text-search).

Both plugins need a small database; each plugin page shows the one-line setup.


## Sitemap

See the full [sitemap](https://content.comark.dev/sitemap.md) for all pages.
