---
title: "content.withRef()"
description: "Create an independent Content instance pinned to a branch, tag, or commit."
canonical_url: "https://content.comark.dev/reference/content/with-ref"
---
# content.withRef()

> Create an independent Content instance pinned to a branch, tag, or commit.

## `content.withRef(ref)`{lang="ts"}

Creates a new Content instance with the same name, options, and plugins as the current one, pinned to a branch, tag, commit SHA, or another source-specific reference. The current instance isn't mutated.

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

export const content = comarkContent({
  source: github({ repo: 'org/docs', branch: 'main', path: 'content' }),
})

const preview = content.withRef('feature/new-guide')
const page = await preview.get('/guide')
```

### Parameters

- `ref`: a non-empty string. Passed to the source's [`withRef`](https://content.comark.dev/sources/custom#interface-withref) when it has one; a source without versioned data (`fs()`) is reused as it is.

### Returns

A new instance with the same type and plugin methods. [`content.ref`](#content-ref-and-content-key) holds the ref; calling `withRef()` on a pinned instance replaces it.

## What a pinned instance owns

Each instance returned by `withRef()` has its own:

- [`init()`](https://content.comark.dev/reference/content/init) lifecycle and [`status`](https://content.comark.dev/reference/content/status)
- index and navigation
- cache namespace: the persisted index, parsed and raw bodies, and HTTP artifacts are stored under a prefix derived from the name and ref, so pinned instances share one driver without reading each other's entries
- hooks and plugin state; plugin `setup()` runs again for the new instance
- request handler

Sources that implement `withRef` are recreated for the ref: the built-in [GitHub source](https://content.comark.dev/sources/github) reads its tree and raw files at that ref, and [`withSnapshot()`](https://content.comark.dev/sources/snapshot#withsnapshot) pins its origin and passes the ref to its loaders. The public `content.cache` keys don't change; only the stored keys do.

```ts [isolation.ts]
const preview = content.withRef(commitSha)

await preview.navigation() // initializes the preview instance only

content.status // 'created'
preview.status // 'initialized-partial'
```

## `content.ref` and `content.key`

`content.ref` is the ref the instance is pinned to, or `undefined` on the default instance. `content.key` is a short opaque identifier derived from the name and ref (`''` on the default instance). Plugins that persist state in shared storage scope it with `key`: the [`sqlQuery`](https://content.comark.dev/plugins/built-in/sql-query) plugin names its tables by it, and [full-text search](https://content.comark.dev/plugins/built-in/full-text-search) keys its rows by it, so two pinned instances sharing one database never collide.

## Build artifacts at another ref

A snapshot built on a pinned instance carries its ref. When a pinned instance loads an artifact stamped with another ref, the artifact is never used as the index, since a file removed between the two commits would still be listed. The index is read from the source at the instance's ref, and the artifact supplies every body whose `meta.hash` still matches. A new commit therefore costs one frontmatter walk plus a full parse of the files that changed. See [which bodies hydrate](https://content.comark.dev/advanced/artifacts-and-hydration#which-bodies-hydrate).

To get that reuse, build the artifact on a pinned instance:

```ts [build.ts]
const built = content.withRef(process.env.VERCEL_GIT_COMMIT_SHA!)
await writeFile('snapshot.json', JSON.stringify(await built.snapshot()))
```

## Reuse and lifecycle

`withRef()` constructs a new instance on every call. Keep the returned instance for as long as you serve that ref instead of recreating it per read. When you replace it, call [`dispose()`](https://content.comark.dev/reference/content/dispose) on the old one; when the ref is gone for good (a deleted preview branch), call [`clean()`](https://content.comark.dev/reference/content/clean) to delete what it persisted.

For production content backed by Git, resolve the branch to a commit SHA and pin to the SHA. A SHA is immutable, so the instance's index and cache namespace stay valid for as long as you keep them. The [GitHub source](https://content.comark.dev/sources/github#production-serve-one-commit-and-follow-the-branch) page walks through the pattern.

Mutations ([`update()`](https://content.comark.dev/reference/content/update), [`ingest()`](https://content.comark.dev/reference/content/ingest), [`remove()`](https://content.comark.dev/reference/content/remove)) are allowed on a pinned instance and write into its namespace. We recommend against them: a ref namespace is assumed to hold exactly the content of its commit, which is what makes it safe to share and to warm ahead of time. [`refresh()`](https://content.comark.dev/reference/content/refresh) re-walks the same commit and is harmless.

To pin several instances at once, see [`hub.withRefs()`](https://content.comark.dev/reference/content-hub#withrefs).


## Sitemap

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