Notion Sync
Bi-directional sync and management for Notion pages and databases. Use when working with Notion workspaces for collaborative editing, research tracking, proj...
Bi-directional sync and management for Notion pages and databases. Use when working with Notion workspaces for collaborative editing, research tracking, proj...
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Bi-directional sync between markdown files and Notion pages, plus database management utilities for research tracking and project management.
From v2.0: Replace
--token "ntn_..." with --token-file, --token-stdin, or NOTION_API_KEY env var. Bare --token is no longer accepted (credentials should never appear in process listings).
From v1.x: See v2.0 changelog for migration details.
ntn_ or secret_)Create a new integration (or use an existing one)
Copy the "Internal Integration Token"
Pass the token using one of these methods (priority order used by scripts):
Option A — Token file (recommended):
echo "ntn_your_token" > ~/.notion-token && chmod 600 ~/.notion-token node scripts/search-notion.js "query" --token-file ~/.notion-token
Option B — Stdin pipe:
echo "$NOTION_API_KEY" | node scripts/search-notion.js "query" --token-stdin
Option C — Environment variable:
export NOTION_API_KEY="ntn_your_token" node scripts/search-notion.js "query"
Auto default: If
~/.notion-token exists, scripts use it automatically even without --token-file.
Share your Notion pages/databases with the integration:
All scripts support a global
--json flag.
{ "error": "..." }Example:
node scripts/query-database.js <db-id> --limit 5 --json
Scripts that read/write local files are restricted to the current working directory by default.
md-to-notion.js, add-to-database.js, notion-to-md.js, watch-notion.js--allow-unsafe-pathsExamples:
# Default (safe): path must be inside current workspace node scripts/md-to-notion.js docs/draft.md <parent-id> "Draft"Intentional override (outside workspace)
node scripts/notion-to-md.js <page-id> ~/Downloads/export.md --allow-unsafe-paths
Search across your Notion workspace by title or content.
node scripts/search-notion.js "<query>" [--filter page|database] [--limit 10] [--json]
Examples:
# Search for newsletter-related pages node scripts/search-notion.js "newsletter"Find only databases
node scripts/search-notion.js "research" --filter database
Limit results
node scripts/search-notion.js "AI" --limit 5
Output:
[ { "id": "page-id-here", "object": "page", "title": "Newsletter Draft", "url": "https://notion.so/...", "lastEdited": "2026-02-01T09:00:00.000Z" } ]
Query database contents with advanced filters and sorting.
node scripts/query-database.js <database-id> [--filter <json>] [--sort <json>] [--limit 10] [--json]
Examples:
# Get all items node scripts/query-database.js xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxFilter by Status = "Complete"
node scripts/query-database.js <db-id>
--filter '{"property": "Status", "select": {"equals": "Complete"}}'Filter by Tags containing "AI"
node scripts/query-database.js <db-id>
--filter '{"property": "Tags", "multi_select": {"contains": "AI"}}'Sort by Date descending
node scripts/query-database.js <db-id>
--sort '[{"property": "Date", "direction": "descending"}]'Combine filter + sort
node scripts/query-database.js <db-id>
--filter '{"property": "Status", "select": {"equals": "Complete"}}'
--sort '[{"property": "Date", "direction": "descending"}]'
Common filter patterns:
{"property": "Status", "select": {"equals": "Done"}}{"property": "Tags", "multi_select": {"contains": "AI"}}{"property": "Date", "date": {"after": "2024-01-01"}}{"property": "Published", "checkbox": {"equals": true}}{"property": "Count", "number": {"greater_than": 100}}Update properties for database pages (status, tags, dates, etc.).
node scripts/update-page-properties.js <page-id> <property-name> <value> [--type <type>] [--json]
Supported types: select, multi_select, checkbox, number, url, email, date, rich_text
Examples:
# Set status node scripts/update-page-properties.js <page-id> Status "Complete" --type selectAdd multiple tags
node scripts/update-page-properties.js <page-id> Tags "AI,Leadership,Research" --type multi_select
Set checkbox
node scripts/update-page-properties.js <page-id> Published true --type checkbox
Set date
node scripts/update-page-properties.js <page-id> "Publish Date" "2024-02-01" --type date
Set URL
node scripts/update-page-properties.js <page-id> "Source URL" "https://example.com" --type url
Set number
node scripts/update-page-properties.js <page-id> "Word Count" 1200 --type number
Batch update a single property across multiple pages in one command.
Mode 1 — Query + Update:
node scripts/batch-update.js <database-id> <property-name> <value> --filter '<json>' [--type select] [--dry-run] [--limit 100]
Example:
node scripts/batch-update.js <db-id> Status Review \ --filter '{"property":"Status","select":{"equals":"Draft"}}' \ --type select
Mode 2 — Page IDs from stdin:
echo "page-id-1\npage-id-2\npage-id-3" | \ node scripts/batch-update.js --stdin <property-name> <value> [--type select] [--dry-run]
Features:
--dry-run: prints pages that would be updated (with current property value) without writing--limit <n>: max pages to process (default 100)has_more/next_cursor) up to limitPush markdown content to Notion with full formatting support.
node scripts/md-to-notion.js \ "<markdown-file-path>" \ "<notion-parent-page-id>" \ "<page-title>" [--json] [--allow-unsafe-paths]
Example:
node scripts/md-to-notion.js \ "projects/newsletter-draft.md" \ "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" \ "Newsletter Draft - Feb 2026"
Supported formatting:
Features:
Output:
Parsed 294 blocks from markdown ✓ Created page: https://www.notion.so/[title-and-id] ✓ Appended 100 blocks (100-200) ✓ Appended 94 blocks (200-294)✅ Successfully created Notion page!
Pull Notion page content and convert to markdown.
node scripts/notion-to-md.js <page-id> [output-file] [--json] [--allow-unsafe-paths]
Example:
node scripts/notion-to-md.js \ "abc123-example-page-id-456def" \ "newsletter-updated.md"
Features:
Monitor Notion pages for edits and compare with local markdown files.
node scripts/watch-notion.js "<page-id>" "<local-markdown-path>" [--state-file <path>] [--json] [--allow-unsafe-paths]
Example:
node scripts/watch-notion.js \ "abc123-example-page-id-456def" \ "projects/newsletter-draft.md"
State tracking: By default maintains state in
memory/notion-watch-state.json (relative to current working directory). You can override with --state-file <path> (supports ~ expansion):
node scripts/watch-notion.js "<page-id>" "<local-path>" --state-file ~/.cache/notion-watch-state.json
Default state schema:
{ "pages": { "<page-id>": { "lastEditedTime": "2026-01-30T08:57:00.000Z", "lastChecked": "2026-01-31T19:41:54.000Z", "title": "Your Page Title" } } }
Output:
{ "pageId": "<page-id>", "title": "Your Page Title", "lastEditedTime": "2026-01-30T08:57:00.000Z", "hasChanges": false, "localPath": "/path/to/your-draft.md", "actions": ["✓ No changes since last check"] }
Automated monitoring: Schedule periodic checks using cron, CI pipelines, or any task scheduler:
# Example: cron job every 2 hours during work hours 0 9-21/2 * * * cd /path/to/workspace && node scripts/watch-notion.js "<page-id>" "<local-path>"
The script outputs JSON — pipe it to any notification system when
hasChanges is true.
Add a markdown file as a new page in any Notion database.
node scripts/add-to-database.js <database-id> "<page-title>" <markdown-file-path> [--json] [--allow-unsafe-paths]
Examples:
# Add research output node scripts/add-to-database.js \ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \ "Research Report - Feb 2026" \ projects/research-insights.mdAdd project notes
node scripts/add-to-database.js
<project-db-id>
"Sprint Retrospective"
docs/retro-2026-02.mdAdd meeting notes
node scripts/add-to-database.js
<notes-db-id>
"Weekly Team Sync"
notes/sync-2026-02-06.md
Features:
Note: Additional properties (Type, Tags, Status, etc.) must be set manually in Notion UI after creation.
node scripts/get-database-schema.js <database-id> [--json]
Example output:
{ "object": "database", "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "title": [{"plain_text": "Ax Resources"}], "properties": { "Name": {"type": "title"}, "Type": {"type": "select"}, "Tags": {"type": "multi_select"} } }
Use when:
node scripts/delete-notion-page.js <page-id> [--json]
Note: This archives the page (sets
archived: true), not permanent deletion.
Push local draft to Notion:
node scripts/md-to-notion.js draft.md <parent-id> "Draft Title"
User edits in Notion (anywhere, any device)
Monitor for changes:
node scripts/watch-notion.js <page-id> <local-path> # Returns hasChanges: true when edited
Pull updates back:
node scripts/notion-to-md.js <page-id> draft-updated.md
Repeat as needed (update same page, don't create v2/v3/etc.)
Generate research locally (e.g., via sub-agent)
Sync to Notion database:
node scripts/add-research-to-db.js
User adds metadata in Notion UI (Type, Tags, Status properties)
Access from anywhere via Notion web/mobile
From Notion URL:
https://notion.so/Page-Title-abc123-example-page-id-456def
Extract:
abc123-example-page-id-456def (last part after title)
Or use the 32-char format:
abc123examplepageid456def (hyphens optional)
"Could not find page" error:
"Module not found" error:
Rate limiting:
Core Sync:
Search & Query:
Database Management:
Utilities:
All scripts use only built-in Node.js modules (https, fs) - no external dependencies required.
No automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.