Claude-code-plugins-plus notion-upgrade-migration
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/notion-pack/skills/notion-upgrade-migration" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-notion-upgrade-migration && rm -rf "$T"
manifest:
plugins/saas-packs/notion-pack/skills/notion-upgrade-migration/SKILL.mdsource content
Notion Upgrade & Migration
Overview
Step-by-step guide for upgrading
@notionhq/client (Node.js) and notion-client (Python) SDK versions, migrating between Notion API versions, handling breaking changes, and adopting newly released features. Covers the current stable API version 2022-06-28 and the SDK feature timeline through v2.x.
Prerequisites
- Existing project with
or@notionhq/client
installednotion-client - Git repository with clean working tree (no uncommitted changes)
- Test suite covering Notion API calls (or willingness to add verification tests)
environment variable configuredNOTION_TOKEN
Instructions
Step 1: Audit Current Versions and API Surface
Determine what you are running today before changing anything.
# Node.js — check installed SDK version npm ls @notionhq/client # Node.js — check latest available npm view @notionhq/client version # Python — check installed SDK version pip show notion-client 2>/dev/null | grep Version # Python — check latest available pip index versions notion-client 2>/dev/null | head -1 # Find which API version your code specifies grep -rn "notionVersion\|Notion-Version\|notion_version" src/ lib/ app/ 2>/dev/null
Record the current SDK version and API version before proceeding. If no
notionVersion is set explicitly, the SDK uses its built-in default (typically 2022-06-28 for current releases).
SDK version history — key milestones:
| SDK Version | Notable Additions |
|---|---|
| Comments API support (, ) |
| Status property type in database schemas |
| Unique ID property, verification property |
| Improved TypeScript discriminated unions for block types |
| Current stable — bug fixes, dependency updates |
API version timeline:
| API Version | Key Changes |
|---|---|
| Rich text standardization, consistent pagination |
| Current stable — most tutorials and production apps use this |
Step 2: Perform the Upgrade
Create an isolated branch, upgrade the package, and address breaking changes before merging.
Node.js upgrade:
# Create upgrade branch git checkout -b upgrade/notionhq-client-$(npm view @notionhq/client version) # Upgrade to latest npm install @notionhq/client@latest # Review what changed npm ls @notionhq/client git diff package.json package-lock.json
Python upgrade:
git checkout -b upgrade/notion-client-$(pip show notion-client 2>/dev/null | grep Version | awk '{print $2}') pip install --upgrade notion-client # Verify pip show notion-client | grep Version
Breaking changes to check after any major version bump:
// 1. Import paths — endpoint types moved in some releases // OLD (pre-2.2.x): import type { QueryDatabaseResponse } from '@notionhq/client/build/src/api-endpoints'; // CURRENT (2.2.x): import type { PageObjectResponse, DatabaseObjectResponse, BlockObjectResponse, QueryDatabaseResponse, } from '@notionhq/client/build/src/api-endpoints'; // 2. Error handling imports are stable across all 2.x versions import { Client, isNotionClientError, APIErrorCode, ClientErrorCode } from '@notionhq/client'; // 3. New property types — code must handle unknown types gracefully function extractProperty(prop: any): string { switch (prop.type) { case 'title': return prop.title.map((t: any) => t.plain_text).join(''); case 'rich_text': return prop.rich_text.map((t: any) => t.plain_text).join(''); case 'status': return prop.status?.name ?? ''; // Added in 2.2.3 case 'unique_id': return String(prop.unique_id?.number ?? ''); // Added in 2.2.4 default: return `[unhandled: ${prop.type}]`; } } // 4. Pin API version explicitly for reproducible behavior const notion = new Client({ auth: process.env.NOTION_TOKEN, notionVersion: '2022-06-28', // Always pin — do not rely on SDK default });
Python breaking changes:
from notion_client import Client, APIResponseError # Pin API version explicitly notion = Client( auth=os.environ["NOTION_TOKEN"], notion_version="2022-06-28", # Explicit pin ) # New in recent versions: comments API comments = notion.comments.list(block_id=page_id) # Status property (requires SDK that supports it) # Returns: {"type": "status", "status": {"name": "In Progress", "color": "blue"}}
Step 3: Verify and Test the Upgrade
Run targeted verification tests to confirm nothing broke. Test each API surface your application uses.
import { Client } from '@notionhq/client'; const notion = new Client({ auth: process.env.NOTION_TOKEN, notionVersion: '2022-06-28', }); // Test 1: Authentication and user listing async function verifyAuth(): Promise<void> { const { results } = await notion.users.list({}); console.log(`Auth OK — ${results.length} users found`); } // Test 2: Database query (most common operation) async function verifyDatabaseQuery(databaseId: string): Promise<void> { const response = await notion.databases.query({ database_id: databaseId, page_size: 5, }); console.log(`Query OK — ${response.results.length} pages, has_more=${response.has_more}`); // Verify property types are still parsed correctly for (const page of response.results) { if ('properties' in page) { const types = Object.values(page.properties).map(p => p.type); console.log(` Property types: ${[...new Set(types)].join(', ')}`); } } } // Test 3: Page creation and archival (write path) async function verifyPageLifecycle(databaseId: string): Promise<void> { const page = await notion.pages.create({ parent: { database_id: databaseId }, properties: { Name: { title: [{ text: { content: `Upgrade test ${Date.now()}` } }] }, }, }); console.log(`Create OK — page ${page.id}`); await notion.pages.update({ page_id: page.id, archived: true }); console.log('Archive OK'); } // Test 4: Block operations (read + append) async function verifyBlocks(pageId: string): Promise<void> { const { results } = await notion.blocks.children.list({ block_id: pageId }); console.log(`Block list OK — ${results.length} blocks`); await notion.blocks.children.append({ block_id: pageId, children: [{ paragraph: { rich_text: [{ text: { content: 'Upgrade verification block' } }] }, }], }); console.log('Block append OK'); } // Test 5: Comments API (available since SDK 2.2.0) async function verifyComments(pageId: string): Promise<void> { try { const { results } = await notion.comments.list({ block_id: pageId }); console.log(`Comments OK — ${results.length} comments`); } catch (err) { console.log('Comments API not available in this SDK version'); } } // Run all verification await verifyAuth(); await verifyDatabaseQuery(process.env.TEST_DB_ID!); await verifyPageLifecycle(process.env.TEST_DB_ID!); await verifyBlocks(process.env.TEST_PAGE_ID!); await verifyComments(process.env.TEST_PAGE_ID!);
After all tests pass, merge the upgrade branch:
npm test # Run project test suite git add -A git commit -m "chore: upgrade @notionhq/client to $(npm ls @notionhq/client --depth=0 | grep @notionhq)" git checkout main && git merge -
Output
- SDK upgraded to the latest stable release with exact version pinned in
package.json - API version explicitly set in client initialization (not relying on SDK default)
- New property types (status, unique_id) handled in extraction logic
- All existing API calls verified — database queries, page CRUD, block operations
- Upgrade branch merged with clean test run
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| New property type returned by API that code does not handle | Add a default case to property type switch — see Step 2 |
| Stale page/database ID after workspace migration | Re-share pages with the integration at notion.so/my-integrations |
| Typo or unsupported version string | Use — confirm at developers.notion.com/reference/versioning |
Type errors on imports | Import path changed between SDK major versions | Check for current exports |
| Network or proxy blocking Notion API | Verify DNS, check corporate proxy, test with |
fails for | Python version incompatible | Requires Python 3.7+; use first |
Examples
Rollback After Failed Upgrade
# Revert to exact previous version npm install @notionhq/client@2.2.14 --save-exact # Restore any source changes git checkout -- src/ # Verify rollback npm test npm ls @notionhq/client
Adopting Comments API After Upgrade
// Available since @notionhq/client 2.2.0 // Add a comment to a page await notion.comments.create({ parent: { page_id: pageId }, rich_text: [{ text: { content: 'Automated review comment from CI' } }], }); // List all comments on a page const { results: comments } = await notion.comments.list({ block_id: pageId, }); for (const comment of comments) { const text = comment.rich_text.map(rt => rt.plain_text).join(''); console.log(`${comment.created_by.id}: ${text}`); }
Detecting New Property Types in Existing Databases
// After upgrade, scan databases for new property types your code may not handle async function auditPropertyTypes(databaseId: string): Promise<void> { const db = await notion.databases.retrieve({ database_id: databaseId }); const knownTypes = new Set([ 'title', 'rich_text', 'number', 'select', 'multi_select', 'date', 'checkbox', 'url', 'email', 'phone_number', 'formula', 'relation', 'rollup', 'people', 'files', 'created_time', 'last_edited_time', 'created_by', 'last_edited_by', 'status', 'unique_id', // Newer types ]); for (const [name, prop] of Object.entries(db.properties)) { if (!knownTypes.has(prop.type)) { console.warn(`Unknown property type "${prop.type}" on "${name}" — add handler`); } } }
Deprecation Monitoring Script
#!/usr/bin/env bash # Check for known deprecated patterns in your codebase echo "=== Notion SDK Deprecation Audit ===" # Check for deprecated header format grep -rn "Notion-Version" --include="*.ts" --include="*.js" src/ 2>/dev/null && \ echo "WARN: Raw Notion-Version header found — use client notionVersion option instead" # Check for untyped page responses grep -rn "as any" --include="*.ts" src/ 2>/dev/null | grep -i notion && \ echo "WARN: Type assertions on Notion responses — use PageObjectResponse type" # Check SDK version against latest CURRENT=$(npm ls @notionhq/client --depth=0 2>/dev/null | grep @notionhq | sed 's/.*@//') LATEST=$(npm view @notionhq/client version 2>/dev/null) if [ "$CURRENT" != "$LATEST" ]; then echo "UPDATE: Running $CURRENT, latest is $LATEST" else echo "OK: Running latest ($CURRENT)" fi
Resources
- Notion SDK Releases — changelog for every
version@notionhq/client - API Versioning — version lifecycle and header format
- API Changelog — new endpoints, properties, and breaking changes
- Python notion-client — PyPI page with version history
- API Status — check for ongoing incidents before debugging upgrade issues
Next Steps
After upgrading, apply production patterns from
notion-sdk-patterns and verify rate limit handling with notion-rate-limits.