---
title: "createContentClient()"
description: "Creates a browser-safe HTTP client bound to a server handler endpoint."
canonical_url: "https://content.comark.dev/reference/client/create-content-client"
---
# createContentClient()

> Creates a browser-safe HTTP client bound to a server handler endpoint.

## `createContentClient(name?, options?)`

Creates an HTTP client bound to a server handler endpoint. The returned type is the base client plus whatever methods client plugins contribute.

The signature mirrors [`comarkContent(name?, options)`](https://content.comark.dev/reference/content/comark-content): an optional instance name first, then options.

**Parameters:**

- `name?`: the instance this client is bound to. See [Name](#name).
- `options?`: a [`ContentClientOptions`](https://content.comark.dev/reference/types/client#contentclientoptions) object (plus an optional `plugins` array). See [Options](#options).

**Returns:** [`ContentClient`](https://content.comark.dev/reference/types/client#contentclient)` & <plugin methods>`, the base client whose methods are always present, extended with any methods that client plugins contribute.

```ts [usage.ts]
import { createContentClient } from 'comark-content/client'

// Unbound: everything the endpoint serves.
export const content = createContentClient({ basePath: '/api/content' })

// Bound to one instance of a hub endpoint.
export const blog = createContentClient('blog', { basePath: '/api/content' })
```

## Name

Binds the client to one [instance](https://content.comark.dev/reference/content/comark-content#name). It does two things at once:

- `get()` and `list()` narrow to that instance's [generated types](https://content.comark.dev/guide/typescript), exactly as they do on the server.
- `get()` and `list()` ask the endpoint for that instance only.

```ts [named.ts]
const blog = createContentClient('blog', { basePath: '/api/content' })
const posts = await blog.list() // GET /api/content/list/["blog"]
const post = await blog.get('/hello') // GET /api/content/get/hello?instance=blog
```

The scoping matters against a [hub](https://content.comark.dev/advanced/hub) endpoint, which serves several instances. Without it, `list()` would return every instance's items under a type that claims otherwise, and `get()` on a path two instances hold would return whichever instance [registered first](https://content.comark.dev/advanced/hub#collisions-first-registered-wins) — not necessarily yours. An endpoint serving a single instance accepts its own name and answers `404` for any other, so a bound client fails loudly when pointed at the wrong endpoint.

Omit the name and the client is unbound: `list()` returns everything the endpoint serves, `get()` resolves across every instance, and results widen to the registry-wide union. That is the right shape for a hub endpoint you want to read as a whole.

## Options

`createContentClient()` accepts the following options:

| Option                          | Type                                                                                              | Default          | Description                                                                                        |
| ------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------- |
| [`baseURL`](#options-baseurl)   | `string`                                                                                          | `''`             | Origin of the server handler (empty for same-origin).                                              |
| [`basePath`](#options-basepath) | `string`                                                                                          | `'/api/content'` | Path where [`content.handler()`](https://content.comark.dev/reference/content/handler) is mounted. |
| [`fetch`](#options-fetch)       | [`ContentFetch`](https://content.comark.dev/reference/types/client#contentfetch)                  | global `fetch`   | Fetch implementation used for every request.                                                       |
| [`plugins`](#options-plugins)   | [`ContentClientPlugin[]`](https://content.comark.dev/reference/types/plugins#contentclientplugin) | `[]`             | Client plugins to install at construction.                                                         |
| [`hooks`](#options-hooks)       | `NestedHooks<ContentClientHooks>`                                                                 | `undefined`      | Local hooks emitted after client reads.                                                            |

### `baseURL`

The origin the client prefixes onto requests. Leave it empty for a same-origin app; set it (for example `https://docs.example.com`) to read from a Content instance hosted elsewhere.

### `basePath`

The path the server handler is mounted at. Must match the `basePath` passed to [`comarkContent`](https://content.comark.dev/reference/content/comark-content). Defaults to `/api/content`.

### `fetch`

A custom [`ContentFetch`](https://content.comark.dev/reference/types/client#contentfetch) (`(url, options?) => Promise<T>`). Defaults to the global `fetch`. Pass Nuxt's `$fetch`, an authenticated wrapper, or a mock in tests.

### `plugins`

Client plugins built with [`defineContentClientPlugin`](https://content.comark.dev/reference/plugins/define-content-client-plugin). They add methods to the returned client, mirroring the Content instance plugin they pair with.

### `hooks`

The client emits the same [`read:after`](https://content.comark.dev/reference/content/hooks#readafter) context and tags as a server Content instance for `get()`, `list()`, `navigation()`, and the plugin reads `query()` and `search()`. Hooks run locally after the HTTP request resolves; nothing is serialized or sent to the server.

```ts [client-tags.ts]
const content = createContentClient({
  hooks: {
    'read:after': ({ tags }) => tags.forEach(cacheTag),
  },
})
```

The bus is also available as `content.hooks` for later subscriptions, and client plugins call `content.callReadHook(operation, input, result)` to emit their own operations.

## Usage

```ts [app/content.ts]
import { createContentClient } from 'comark-content/client'

export const content = createContentClient({ basePath: '/api/content' })
```


## Sitemap

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