> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirage.strukto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Notion

> Mount Notion pages and databases as a Mirage filesystem.

`NotionVFS` exposes a Notion workspace as a filesystem. The Node SDK talks to the Notion REST API with an integration token; the Browser SDK talks to Notion's MCP server with an OAuth client provider so secrets stay off the page.

## Node

```bash theme={null}
pnpm add @struktoai/mirage-node
```

```ts theme={null}
import { MountMode, NotionVFS, Workspace } from '@struktoai/mirage-node'

const notion = new NotionVFS({ apiKey: process.env.NOTION_API_KEY! })

const ws = new Workspace({ '/notion': notion }, { mode: MountMode.READ })
await ws.shell('ls /notion/pages/')
```

| Field | Default | Notes |
| - | - | - |
| `apiKey` | required | Notion internal integration token. Redacted in snapshots. |
| `baseUrl` | `https://api.notion.com/v1` | Override for testing against a mock server. |

## Browser

```bash theme={null}
pnpm add @struktoai/mirage-browser @modelcontextprotocol/client
```

```ts theme={null}
import { MountMode, NotionVFS, Workspace } from '@struktoai/mirage-browser'

const notion = new NotionVFS({
  authProvider, // OAuthClientProvider from @modelcontextprotocol/client
})

const ws = new Workspace({ '/notion': notion }, { mode: MountMode.READ })
await ws.shell('ls /notion/')
```

| Field | Default | Notes |
| - | - | - |
| `authProvider` | required | `OAuthClientProvider` from `@modelcontextprotocol/client`. Redacted in snapshots. |
| `serverUrl` | Notion's hosted MCP endpoint | Override if you proxy MCP through your own URL. |

## Mount mode

`read`, `write` (page edits via the MCP server in the browser SDK).

## Acting on Notion

Acting on Notion (creating, editing and trashing pages, querying data
sources, and every route that has no typed verb) goes through the
[ntn CLI](/typescript/cli/ntn) when installed.

## Layout

```text theme={null}
/notion/
  pages/
    <page-title>__<page-id>/
      page.json
      <child-page-title>__<child-id>/
        page.json
        ...
  databases/
    <database-title>__<database-id>/
      database.json
      <data-source-name>__<data-source-id>/
        data_source.json
        rows.jsonl
```

Since the `2025-09-03` API generation a database is a container of **data
sources**, and both the column schema and the rows live on the data
source: `data_source.json` and `rows.jsonl`.
`database.json` is the container's identity plus the `data_sources` stubs
that name the directories beneath it, and carries **no** `properties`.
The shape is identical to the Python connector:

```json theme={null}
{
  "database_id": "eeee1111-2222-3333-4444-555566667777",
  "title": "Tasks",
  "url": "https://www.notion.so/eeee1111222233334444555566667777",
  "created_time": "2026-01-01T00:00:00.000Z",
  "last_edited_time": "2026-01-02T00:00:00.000Z",
  "parent": { "type": "workspace", "workspace": true },
  "archived": false,
  "is_inline": false,
  "data_sources": [
    { "id": "d5000000-2222-3333-4444-555566667777", "name": "Tasks" }
  ]
}
```

`data_source.json` holds the typed column schema under `properties`, and
`rows.jsonl` holds every row, one JSON object per line: the row's
`page.json` without the body, plus `path`, where that `page.json` is below
the data source directory. The rows are one file rather than a directory
each, because a query answers a hundred rows' cells in one call while
every row directory costs calls of its own to enter.

A database row is itself a page: its `page.json` reports `parent_type` of
`data_source_id`, and its cell values ride in the same file under
`properties`. Row directories are not listed; open one by the `path` on
its line. For full `rows.jsonl` and `page.json` field details and
supported edits see the [Python Notion docs](/python/vfs/notion).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.