---
title: "content.get()"
description: "Read one document by its public path, parsing and caching the body on demand."
canonical_url: "https://content.comark.dev/reference/content/get"
---
# content.get()

> Read one document by its public path, parsing and caching the body on demand.

## `content.get(path, options?)`

Reads one document by its public path, parsing the body (and caching it) on demand.

Public paths are normalized to lowercase when indexed. Path and source-key lookup is case-insensitive, and the returned file uses the normalized lowercase path. See [Files and paths](https://content.comark.dev/guide/files-and-paths#lowercase-paths) for case-only duplicates.

**Parameters:**

- `path`: public path of the document (for example `/posts/hello`), or its file key inside the source (`posts/hello.md`, optionally prefixed with the instance name as in `meta.key`). Matching is case-insensitive.
- `options?`: optional, see [Options](#options). Pass `fresh: true` to read the document from its source now.

**Returns:** `Promise<`[`ContentFile`](https://content.comark.dev/reference/types/content#contentfiletdata-tmeta)` | null | undefined>`, where `null` means no entry maps to the path and `undefined` means the entry exists but is not a document (for example a media file).

```ts [usage.ts]
const page = await content.get('/posts/hello')
if (!page) return notFound()

page.data     // frontmatter (typed)
page.nodes    // the parsed MarkdownDocument nodes
page.meta     // { kind, type, key, source, extension, stem, partial, hash }
```

With [generated types](https://content.comark.dev/guide/typescript), a known path auto-narrows the return type; otherwise pass a type parameter: `content.get<PostFrontmatter>('/posts/hello')`.

## Options

`get()` accepts one option:

| Option                    | Type      | Default | Description                                                                    |
| ------------------------- | --------- | ------- | ------------------------------------------------------------------------------ |
| [`fresh`](#options-fresh) | `boolean` | `false` | Ask the origin now: skip the cache and the snapshot, re-parse from the source. |

### `fresh`

By default `get()` looks for the body in the cache, then in the [snapshot](https://content.comark.dev/sources/snapshot) when the source has one, and only then reads and parses it from the source. Pass `fresh: true` to skip the first two and re-read and re-parse the document straight from its source, refreshing the cached entry in the process.

```ts [fresh.ts]
const post = await content.get('blog/post.md', { fresh: true })
```

With a **file key** (`blog/post.md`) the key already names the file, so the index isn't consulted and `init()` doesn't run, whatever the instance's state. With a **public path** (`/blog/post`) the index is loaded to resolve the file first. A fresh read that fails is an error; it never falls back to a cached or snapshot body. A file the source doesn't have returns `null`.

### Reading by file key

On a cold instance, a file key with a registered extension reads straight from the source and skips `init()`, for a raw source (`fs()`, `github()`) or a parsed source with a per-file `get()`. This is the cheapest read for a single document in a serverless function. A key the source doesn't have falls back to the index lookup, so a key that differs only by case still resolves.

A source wrapped with [`withSnapshot()`](https://content.comark.dev/sources/snapshot) is the exception. Two versions of a body can exist there, the build's and the runtime's, and only the index can tell which one is current, or that the document was removed since the build. Those reads load the index first (one artifact read, no source access) and then serve the body from the snapshot.

## Usage

```ts [usage.ts]
const page = await content.get('/posts/hello')
```


## Sitemap

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