---
title: "Media plugin"
description: "Serve binary files (images, fonts, videos) from your source so they can live alongside your content."
canonical_url: "https://content.comark.dev/plugins/built-in/media"
---
# Media plugin

> Serve binary files (images, fonts, videos) from your source so they can live alongside your content.

The `media` plugin makes the Content instance treat binary files (images, fonts, video, PDFs) as `kind: 'media'` entries. They are listed alongside documents in the manifest and the plugin serves their bytes at their public `path`.

## Usage

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

export const content = comarkContent({
  source: github({ repo: 'org/assets', branch: 'main', path: 'public', prefix: '/assets' }),
  plugins: [media()],
})
```

The plugin adds a `content.media` namespace. Read an item's metadata with `content.stat()` and its bytes with `content.media.get()`, then serve them with the correct content type:

```ts [serve-media.ts]
import { content } from './content'

export async function serveLogo() {
  const item = content.stat('/assets/logo.svg')
  //    ^? ContentListFile - { path: '/assets/logo.svg', data, meta: { kind: 'media', type: 'image/svg+xml', ... } }
  if (!item) return new Response('Not found', { status: 404 })

  const raw = await content.media.get('/assets/logo.svg')
  //    ^? unknown: the raw bytes (Uint8Array | string), or null
  if (raw == null) return new Response('Not found', { status: 404 })

  return new Response(raw as BodyInit, { headers: { 'content-type': item.meta.type } })
}
```

::tip{to="https://content.comark.dev/integrations/vite"}
With the plugin registered on the build-time instance, the Vite plugin serves media in development and emits every media entry into the build output, so the same URLs your client uses in dev resolve as static assets in production.
::

---

## API

One factory plus the `content.media` namespace it adds:

### `media(options?)`{lang="ts"}

Returns a [`ContentPlugin`](https://content.comark.dev/reference/types/plugins#contentplugin) that registers a parser for the configured extensions (marking matching files as `kind: 'media'`) and adds the `content.media.get()` and `content.media.list()` methods.

**Parameters:**

- `options?`: see [Options](#options).

**Returns:** [`ContentPlugin`](https://content.comark.dev/reference/types/plugins#contentplugin)

### `content.media.get(key)`

Added by the plugin. Fetches the raw bytes of a media item by public path or `meta.key`. Calls `content.init()`, resolves the item via [`content.stat()`](https://content.comark.dev/reference/content/stat), then reads it from its source.

**Parameters:**

- `key`: `string`, the media item's public path (`/assets/logo.svg`) or its [`meta.key`](https://content.comark.dev/guide/files-and-paths#internal-identifiers).

**Returns:** `Promise<unknown>` - the raw bytes (`Uint8Array` or `string` at runtime), or `null` when no matching item exists.

### `content.media.list()`

Added by the plugin. Lists every `kind: 'media'` entry in the manifest.

**Returns:** `Promise<`[`ContentListFile`](https://content.comark.dev/reference/types/content#contentlistfiletdata)`[]>`

---

## Options

`media(options?)` accepts one option:

| Option                              | Type               | Default                    | Description                            |
| ----------------------------------- | ------------------ | -------------------------- | -------------------------------------- |
| [`extensions`](#options-extensions) | ```.${string}`[]`` | `DEFAULT_MEDIA_EXTENSIONS` | File extensions to recognize as media. |

### `extensions`

The list of file extensions the plugin registers as media. When omitted, the built-in `DEFAULT_MEDIA_EXTENSIONS` list is used:

```ts
['.png', '.jpg', '.jpeg', '.gif', '.webp', '.avif', '.svg', '.ico', '.bmp',
 '.mp4', '.webm', '.ogg', '.mp3', '.wav', '.aac', '.pdf']
```

MIME types are looked up from an internal MIME type map. To override the list (for instance to drop `.pdf` or add `.woff2`) pass `extensions`:

```ts [override.ts]
import media from 'comark-content/plugins/media'

media({
  extensions: ['.png', '.svg', '.webp', '.mp4', '.woff2'],
})
```

::warning
`extensions` **replaces** the default list rather than extending it. Include every extension you want to recognize.
::

**Default:** `DEFAULT_MEDIA_EXTENSIONS`


## Sitemap

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