Skip to main content
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

Fields marked secret are redacted in snapshots.

Browser

Fields marked secret are redacted in snapshots.

Mount mode

read. Edit pages through the ntn CLI.

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 when installed.

VFS.md

The VFS.md an agent reads with Notion mounted at /<path>.

Virtual Filesystem

VFS Layout

/<path>
  • page.json holds the page’s metadata, its body rendered as Markdown and its raw blocks (nested blocks under children).
  • A database is a container plus one or more data sources. database.json holds the container’s identity and its data_sources stubs, data_source.json the typed property schema, and rows.jsonl the rows, one JSON line each: the row page’s page.json without the body, plus path, that page.json’s path below the data source directory. Row directories are not listed; open one by its path.
  • Titles are sanitized. Don’t construct paths: ls the parent directory, or take a row’s path from rows.jsonl.
  • ntn takes ids as positional operands, not flags: ntn pages get <page-id>, ntn datasources query <data-source-id>, ntn datasources resolve <database-id>.

Supported Unix Commands for VFS

Unix commands work on each path as on a local filesystem, as far as the path supports them:

Limitations of Unix Commands for VFS

Where a path differs from a local filesystem:Run man <cmd> or <cmd> --help for one command’s usage.
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:
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.

Integration

What Notion answers through its own API, so fewer files are read. Integration explains each command.