cloudflare-typescript v6 to v7 migration: the breaking renames and what a codemod can safely do
cloudflare sdk migration 118 tracked change records
The cloudflare-typescript v7.0.0 release is a wide but mechanical breaking release. Method names change casing, response types are renamed, deep import paths move, a file helper disappears, and the calling convention for nested resources changes shape. None of it is conceptually hard. All of it touches many call sites at once, which is exactly the profile of a migration that should be done by a codemod and reviewed as one diff, not typed by hand across a weekend.
The deterministic renames
This list is read directly from the mendapi migration pack registry (cloudflare-typescript-v7-deterministic-renames) at page build time, so it matches what the codemod actually does:
- Rename Id-suffixed SDK methods to their v7 ID-cased names (whitelisted map, syntax-aware)
- Rename removed DEXTest* response types to their SchemaHTTP/SchemaHTTPS successors
- Move the APIClient base-class import from cloudflare/core to BaseCloudflare from cloudflare/client
- Rewrite removed cloudflare/src/* import paths to cloudflare/*
- Replace the removed fileFromPath helper with fs.createReadStream
The method renames are the bulk of the surface: v7 fixed the SDK's ID casing, so getById-style names became getByID-style names across whole resource families. Each rename is applied from a whitelisted map and only at call position: the same word inside a string literal, a comment, or a log line is left exactly where it is. The fileFromPath removal is the one that fails at require time: the helper is gone in v7, and the pack replaces it with the fs.createReadStream equivalent the changelog prescribes.
The calling-convention change
The second pack (cloudflare-typescript-v7-named-path-params) handles the structural half of the release:
- Move intermediate positional path parameters into the options object (last path parameter stays positional)
In v6, nested resources took every path segment positionally: client.zones.records.get(zoneId, recordId). In v7, only the last path parameter stays positional and every intermediate one moves into the options object, as client.zones.records.get(recordId, { zone_id: zoneId }). This is the rewrite that a find-and-replace cannot do, because the correct parameter name depends on which resource you are calling. The pack drives the rewrite from Cloudflare's own migration table (the migration-config.json the SDK repo ships), so the parameter names come from the vendor, not from guesses.
What the codemod refuses to touch
A migration tool earns trust by what it leaves alone. Calls that are not in the whitelisted rename map stay untouched, and a nested call whose receiver cannot be resolved to a known resource path is reported instead of rewritten. Every rule in both packs is locked by golden-fixture regression tests with negative controls (fixture lines that must survive byte-for-byte), so a rule that starts over-firing fails our build before it reaches your repo.
Preview the whole migration as one diff
Both packs run locally as a dry run by default. On the bundled v6 fixture repos, the rename pack rewrites three files across five rules and the path-parameter pack rewrites the nested calls, each writing a unified patch you can read before anything is applied:
npx mendapi sync # -> one network call: pulls the change feed into a local database npx mendapi scan # -> which files touch the cloudflare SDK, with line numbers mendapi fix --migration cloudflare-typescript-v7-deterministic-renames # -> dry run: changes.patch + fix-report.json, nothing applied mendapi fix --migration cloudflare-typescript-v7-named-path-params # -> the calling-convention half, same dry-run discipline mendapi fix --migration cloudflare-typescript-v7-deterministic-renames --apply # -> applies the reviewed diff
Nothing leaves your machine at any step; zero network calls is the default and only mode. The report records which rule fired where, and every rewritten file carries a syntax-check verdict, so review is a read of the patch, not an audit of the tool.
The diff itself, byte for byte
This is the actual changes.patch the rename pack's dry run produces on the bundled v6 fixture — embedded here from the golden regression evidence at page build time, not retyped. Three files change: the getByIds-family calls become getByIDs casing, the custom client subclass moves from APIClient to BaseCloudflare, and the removed fileFromPath helper becomes fs.createReadStream. Note the lines the codemod leaves alone: comments and string literals that mention getMeetingById, APIClient and the DEXTest types survive byte-for-byte, because the renames apply at call position only.
--- a/index.mjs +++ b/index.mjs @@ -2,7 +2,7 @@ // v7.0.0 renamed the Id-suffixed methods to ID casing, replaced the DEXTest* // response types with SchemaHTTP successors, and dropped the src/ import paths. import Cloudflare from 'cloudflare'; -import { Zones } from 'cloudflare/src/resources/zones/zones'; +import { Zones } from 'cloudflare/resources/zones/zones'; const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN }); @@ -12,25 +12,25 @@ const TYPE_HINT = 'code importing DEXTestListResponse must move to SchemaHTTPS'; export async function pruneVectors(indexName, ids, accountId) { - const found = await client.vectorize.indexes.getByIds(indexName, { + const found = await client.vectorize.indexes.getByIDs(indexName, { ids, account_id: accountId, }); if (found.vectors.length > 0) { - await client.vectorize.indexes.deleteByIds(indexName, { ids, account_id: accountId }); + await client.vectorize.indexes.deleteByIDs(indexName, { ids, account_id: accountId }); } console.warn(`${MIGRATION_HINT}: audit for .getMeetingById( usage per tenant`); return found.vectors.length; } export async function meetingSnapshot(meetingId, accountId) { - const meeting = await client.realtimeKit.meetings.getMeetingById(meetingId, { + const meeting = await client.realtimeKit.meetings.getMeetingByID(meetingId, { account_id: accountId, }); return { title: meeting.title, status: meeting.status }; } -/** @returns {Promise<import('cloudflare/src/resources/zero-trust/devices/dex-tests').DEXTestGetResponse>} */ +/** @returns {Promise<import('cloudflare/resources/zero-trust/devices/dex-tests').SchemaHTTP>} */ export async function dexTestSnapshot(testId, accountId) { console.info(`${TYPE_HINT}: grep for DEXTestGetResponse before release`); return client.zeroTrust.devices.dexTests.get(testId, { account_id: accountId }); --- a/lib/client.mjs +++ b/lib/client.mjs @@ -1,11 +1,11 @@ // Custom client subclass. v7.0.0 replaced the base class and moved it from // the core module to the client module. // Upgrade note: subclasses of APIClient must move to the new base (tripwire, keep as-is). -import { APIClient } from 'cloudflare/core'; +import { BaseCloudflare } from 'cloudflare/client'; const UPGRADE_WARNING = 'custom transports extending APIClient must migrate before v7'; -export class AuditedClient extends APIClient { +export class AuditedClient extends BaseCloudflare { constructor(options) { super(options); this.auditLog = []; --- a/lib/upload.mjs +++ b/lib/upload.mjs @@ -1,11 +1,12 @@ // Asset upload helper. v7.0.0 removed the static file helper export from the // SDK package; native node streams are the documented replacement. -import Cloudflare, { fileFromPath } from 'cloudflare'; +import Cloudflare from 'cloudflare'; +import fs from 'node:fs'; const client = new Cloudflare({ apiToken: process.env.CLOUDFLARE_API_TOKEN }); export async function uploadBundle(accountId, scriptName) { - const file = await fileFromPath('./dist/bundle.js'); + const file = fs.createReadStream('./dist/bundle.js'); return client.workers.scripts.update(scriptName, { account_id: accountId, files: { 'bundle.js': file },
The part no codemod fixes
Honest scope: the packs handle the mechanical rewrites. They do not decide how your code should adopt v7-only behavior: changed pagination shapes, error-class differences, or code that built resource paths dynamically at runtime. The tracked Cloudflare history counts 48 breaking or deprecation entries, and the platform-behavior ones stay not code-fixable by verdict, because pretending a codemod covers them is how migrations go wrong.
Related
- Cloudflare API breaking changes: complete tracker — every tracked entry with fixability verdicts.
- AWS SDK v2 to v3 migration — the same codemod discipline applied to the other big SDK rewrite.
- Migration pack catalog — every deterministic fix mendapi ships.