# AI SDK 7 Migration: Upgrading from AI SDK 6 (What the Codemod Misses)

An **AI SDK 7 migration** looks like a rename job: `system` becomes `instructions`, `onFinish` becomes `onEnd`, and there's a codemod for most of it. I upgraded a real AI SDK 6 app to see what's actually left after the codemod. The codemod ran in 20 seconds and fixed 15 lines, but it fixed only 1 of the 9 tests that broke. The rest were behaviour changes that TypeScript doesn't flag at all, including token usage that silently doubled and OpenTelemetry traces that silently stopped.

Here's the full upgrade path from AI SDK 6 to 7, with every number measured on `ai` 6.0.309 → 7.0.143.

## TL;DR: how do I upgrade to AI SDK 7?

1. Make sure you're on Node.js 22 or later (24 LTS is better). AI SDK 7 drops Node 18 and 20.
2. Commit, then upgrade: `npm i ai@7 @ai-sdk/react@4 @ai-sdk/openai@4` (and your other providers).
3. Run `npx @ai-sdk/codemod v7` from the project root.
4. Run `tsc --noEmit` and fix what's left, mainly tool context.
5. Review the behaviour changes by hand: `usage` and `toolCalls` now cover all steps, `step.response.messages` is per step, `onChunk` gets every stream part, and system messages inside `messages` now throw.
6. If you use OpenTelemetry, install `@ai-sdk/otel` and call `registerTelemetry()`, or your traces stop.

| Stage | TypeScript errors | Failing tests (of 13) | Lines changed |
| --- | --- | --- | --- |
| v6 baseline (`ai` 6.0.309) | 0 | 0 | none |
| Bump to `ai` 7.0.143, no code changes | 6 | 9 | 0 |
| After `npx @ai-sdk/codemod v7` | 2 | 8 | 15 |
| After manual fixes | 0 | 0 | +18 more |

## What's new in AI SDK 7?

AI SDK 7.0 shipped on June 25, 2026, and the current release is `ai` 7.0.143. The headline changes in the [official migration guide](https://ai-sdk.dev/docs/migration-guides/migration-guide-7-0) are:

- **Node.js 22+ and ESM-only packages.** No more CommonJS builds.
- **Renames out of `experimental_`**: `telemetry`, `include`, `onStart`, `onStepStart`, `transcribe`, `generateSpeech`, and tool `context`.
- **New names for old concepts**: `system` → `instructions`, `onFinish` → `onEnd`, `onStepFinish` → `onStepEnd`, `fullStream` → `stream`, `stepCountIs` → `isStepCount`.
- **Results cover every step.** `usage`, `toolCalls`, `toolResults`, `content` and friends are accumulated across a multi-step tool loop, and the old final-step values move to `result.finalStep`.
- **Typed, per-tool context** with `contextSchema` and `toolsContext`, separate from a shared `runtimeContext`.
- **Telemetry as a plug-in.** OpenTelemetry lives in `@ai-sdk/otel`, and telemetry is on by default once you register an integration.
- **Safer defaults**: system messages in `messages` are rejected, request bodies aren't kept in results, and MCP HTTP transports no longer follow redirects.

Most renames keep the old name as a deprecated alias, so your code keeps compiling. That's convenient, and it's also why a type check alone won't tell you whether the migration is done.

## How I tested the upgrade

I wrote a small but realistic AI SDK 6 app, the kind of code you'd find in a Next.js chat product:

- a **tool loop** with `generateText`, a `system` prompt, a weather tool reading `experimental_context`, `stopWhen: stepCountIs(3)`, `onStepFinish` and `onFinish` callbacks logging token usage, and `experimental_telemetry`
- a **streaming chat route** using `streamText`, `convertToModelMessages` and `toUIMessageStreamResponse()`, plus a `fullStream` consumer with an `onChunk` handler
- **structured output** with `experimental_output: Output.object(...)`
- **stored chats** whose first message is `{ role: 'system' }`
- a small **CommonJS script** that does `require('ai')`

Then I wrote 13 tests with `node:test` and the SDK's own `MockLanguageModelV3`, so every run is offline and deterministic. Each test pins down one behaviour the app relies on: the tool gets its context, `usage` is the final step's, the last step's messages hold the whole exchange, and so on. All 13 passed on v6 with zero TypeScript errors.

Versions: `ai` 6.0.309 → 7.0.143, `@ai-sdk/openai` 3.0.130 → 4.0.96, `@ai-sdk/react` 3.0.312 → 4.0.147, `@ai-sdk/codemod` 4.0.3, TypeScript 5.9.3, Node 24.22.

## Step 1: bump the packages (6 type errors, 9 failing tests)

Upgrading the packages without touching code gave 6 TypeScript errors:

- `experimental_context` is gone from both the `generateText` options and the tool's `execute` options (2 errors)
- `experimental_output` is gone as an option and as a result property (2 errors)
- `usage.cachedInputTokens` no longer exists
- the `ToolCallOptions` type is no longer exported

And 9 of 13 tests failed. The scariest failure was one that *didn't* look like a failure: with `experimental_context` gone, the tool threw `Cannot destructure property 'units' of 'experimental_context' as it is undefined`. The SDK turned that into an `error-text` tool result, sent it back to the model, and my mock model still produced a normal answer. The "tool loop works" test passed. A real model would probably apologise or guess, and you'd find out from users.

The CommonJS script, on the other hand, kept working. AI SDK 7 ships only ESM, but Node 24 can `require()` ES modules natively, so `require('ai')` still returned the functions. On older Node versions without `require(esm)` support it will fail, but those versions aren't supported by AI SDK 7 anyway.

## Step 2: run the codemod (2 type errors, 8 failing tests)

```bash
npx @ai-sdk/codemod v7 src test
```

It took 19.8 seconds and changed 15 lines in 4 files:

- `system` → `instructions` (2 places) and `stepCountIs` → `isStepCount`
- `onStepFinish` → `onStepEnd`, `onFinish` → `onEnd`
- `experimental_telemetry` → `telemetry`
- `usage.cachedInputTokens` → `usage.inputTokenDetails.cacheReadTokens`
- `experimental_output` → `output` (option and result)
- `fullStream` → `stream`
- `ToolCallOptions` → `ToolExecutionOptions`
- `{ experimental_context }` → `{ context: experimental_context }` inside the tool's `execute`

Those are all correct, mechanical renames. What it couldn't do:

- **Tool context at the call site.** It left `experimental_context: { units: 'c' }` in the `generateText` call, which is now a type error. The v7 design needs a `contextSchema` on the tool and a `toolsContext` object keyed by tool name, which isn't a rename.
- **The new generic.** It swapped in `ToolExecutionOptions`, which now requires a type argument, so the codemod itself introduced a new type error.
- **Any behaviour change.** It kept `telemetry: { isEnabled: true }` and kept reading `result.usage` and `result.toolCalls` exactly as before, now with different meanings.

The only test it fixed was structured output. Eight still failed.

## Step 3: the behaviour changes you have to fix by hand

![AI SDK 6 to 7 migration steps: TypeScript errors and failing tests after the version bump, the codemod and manual fixes](https://res.cloudinary.com/wasicloudinary/image/upload/v1792271891/fabwaseem/blog/ai-sdk-7-migration/diagram-steps.jpg)

These are the changes that broke tests even after the codemod, with the fix I used for each.

**Tool context.** Declare what each tool needs and pass it per tool:

```ts
export const weather = tool({
  inputSchema: z.object({ city: z.string() }),
  contextSchema: z.object({ units: z.enum(['c', 'f']) }),
  execute: async ({ city }, { context: { units } }) => getWeather(city, units),
})

await generateText({
  model,
  tools: { weather },
  toolsContext: { weather: { units: 'c' } },
  // ...
})
```

The bonus is that `context` is now typed, so the `as { units: ... }` cast goes away.

**Usage now covers all steps.** In my two-step tool loop, `result.usage.totalTokens` went from 15 (final step only) to 30 (both steps), and cached input tokens went from 4 to 8. `totalUsage` is deprecated. If your billing, rate limits or logs read `usage`, decide which number you want. For the old meaning, read `result.finalStep.usage`. The same applies inside `onEnd`: `event.usage` is now all steps and `event.finalStep.usage` is the last step.

**`toolCalls` and friends now cover all steps.** `result.toolCalls.length` went from 0 to 1, because the tool call happened in step 1, not the final step. Same for `toolResults`, `content`, `files`, `sources` and `warnings`. Use `result.finalStep.toolCalls` for the old behaviour.

**`step.response.messages` is per step.** In v6 the last step's `response.messages` held the whole exchange (3 messages: tool call, tool result, answer). In v7 it held 1. If you persist the conversation from it, switch to `result.responseMessages`.

**`onChunk` receives every stream part.** My handler went from seeing 2 chunks (`text-delta` ×2) to 8, including `start`, `start-step`, `text-start`, `text-end`, `finish-step` and `finish`. Guard on `chunk.type` before using it.

**System messages in `messages` throw.** v6 printed a warning; v7 throws `AI_InvalidPromptError: System messages are not allowed in the prompt or messages fields`. That breaks old stored chats. I moved them into `instructions`:

```ts
const instructions = stored.filter(m => m.role === 'system').map(m => m.content).join('\n')
const messages = stored.filter(m => m.role !== 'system')
await generateText({ model, instructions: instructions || undefined, messages })
```

Only use `allowSystemInMessages: true` if every stored message came from your own server code, because a user-supplied system message is a prompt injection.

**Deprecated stream helpers.** `result.toUIMessageStreamResponse()` still works but is deprecated. The stateless replacement is `createUIMessageStreamResponse({ stream: toUIMessageStream({ stream: result.stream }) })`.

With these 18 extra lines across the same 4 files, I was back to 0 TypeScript errors, 13 of 13 tests passing and no deprecation warnings.

## Does OpenTelemetry still work after upgrading to AI SDK 7?

Not by itself. This was the most silent break I found, and none of my tests caught it, so I tested it separately with an in-memory OpenTelemetry exporter.

- **v6** with `experimental_telemetry: { isEnabled: true }` recorded 2 spans: `ai.generateText` and `ai.generateText.doGenerate`.
- **v7**, same code, recorded **0 spans**. No error, no warning.
- **v7** with `@ai-sdk/otel` 1.0.143 and `registerTelemetry(new OpenTelemetry())` at startup recorded 3 spans, with new names: `invoke_agent mock-model-id`, `chat mock-model-id` and `step 1`.

So you need the new package *and* you need to update any dashboard, alert or query that filters on the old `ai.generateText` span names. For Next.js, register it in `instrumentation.ts`:

```ts
import { registerTelemetry } from 'ai'
import { OpenTelemetry } from '@ai-sdk/otel'

registerTelemetry(new OpenTelemetry())
```

Once an integration is registered, every call is traced by default, so you can delete `isEnabled: true` and use `isEnabled: false` to opt out.

## Which AI SDK 7 changes does the codemod catch?

![Which AI SDK 7 changes cause a type error, are fixed by the codemod, or are only caught by tests](https://res.cloudinary.com/wasicloudinary/image/upload/v1792271893/fabwaseem/blog/ai-sdk-7-migration/diagram-matrix.jpg)

The pattern is clear. Renames are covered: either the old name still works as an alias, or TypeScript flags it and the codemod fixes it. Semantic changes are not: all-steps results, per-step messages, `onChunk` and system messages pass the type check and slip past the codemod. Telemetry gets past all three.

If your app has no tests around its AI calls, write a few before you upgrade. Pin down token usage, what you persist, and what your tools receive.

## Should I use the AI SDK migration skill?

Vercel also publishes an agent skill for this upgrade:

```bash
npx skills add vercel/ai --skill migrate-ai-sdk-v6-to-v7
```

Then you ask your coding agent to "use the migrate-ai-sdk-v6-to-v7 skill and migrate my app". The skill is a checklist that points at the migration guide, and it does say the right thing: "When v7 changes semantics, decide whether the app wants the new all-steps behavior or the previous final-step-only behavior." It also covers tool context, `finalStep` and `@ai-sdk/otel`, which the codemod can't.

My suggestion: run the codemod first for the mechanical renames, then let an agent with the skill (or yourself, with this list) work through the behaviour changes, and review that diff carefully. If you haven't used skills before, I explained how they work in [Agent Skills explained](https://www.fabwaseem.com/blog/agent-skills).

## Install size and performance: is AI SDK 7 heavier?

Barely. A fresh install of `ai`, `@ai-sdk/openai`, `@ai-sdk/react` and React was 23.8 MB across 18 packages on v6 and 24.3 MB across 26 packages on v7. The `ai` package itself grew from 7.2 MB to 8.2 MB. It dropped its `@opentelemetry/api` dependency (now in `@ai-sdk/otel`), while `@ai-sdk/react` 4 now pulls in `@ai-sdk/mcp` and `cross-spawn`.

Import time didn't change: `import 'ai'` took 113.5 ms on v6 and 115.4 ms on v7 (30 runs each with hyperfine, against 23.8 ms for an empty Node script), which is within noise.

## Other AI SDK 7 changes worth checking

My test app didn't use these, but grep your code for them:

- **`prepareStep` overrides carry forward.** Returned `instructions` and `messages` now stick for later steps instead of applying to one step.
- **Request and response bodies are excluded by default.** If you log `result.request.body`, opt in with `include: { requestBody: true }`.
- **MCP redirects.** `createMCPClient` HTTP and SSE transports now default to `redirect: 'error'` to block SSRF. If your MCP server redirects, set `redirect: 'follow'`. See my [MCP security guide](https://www.fabwaseem.com/blog/mcp-security) for why that default matters.
- **`needsApproval` is deprecated** in favour of a `toolApproval` setting on the call.
- **Image parts** become `{ type: 'file', mediaType: 'image', data }`.
- **xAI** now uses the Responses API by default, and **OpenAI** reasoning summaries default to `'detailed'` when reasoning is on.
- **Google provider** names drop `GenerativeAI`, for example `createGoogleGenerativeAI` → `createGoogle`.

## Common AI SDK 7 migration mistakes

- **Stopping when `tsc` passes.** Most of the deprecated names still compile. My app had 0 type errors with 8 failing tests in between.
- **Not reviewing the meaning of `usage`.** It now covers all steps. Code that adds up per-step usage and then also adds the final `usage` will now count every step twice.
- **Forgetting `@ai-sdk/otel`.** Traces stop without an error.
- **Trusting a passing "it answers" test.** A tool that throws becomes a tool error the model can talk around.
- **Turning on `allowSystemInMessages` for user data.** Move system prompts to `instructions` instead.

## Key takeaways

- AI SDK 7 needs Node.js 22+ and is ESM-only, but `require('ai')` still worked on Node 24 thanks to native `require(esm)`.
- Bumping `ai` 6.0.309 → 7.0.143 gave 6 TypeScript errors and 9 of 13 failing tests on a realistic app.
- `npx @ai-sdk/codemod v7` took 20 seconds and fixed 15 lines, but only 1 of the 9 failing tests.
- `usage`, `toolCalls` and the other results now cover all steps; in my tool loop, usage went from 15 to 30 tokens. Use `finalStep` for the old meaning.
- Tool context moved to `contextSchema` plus `toolsContext`; without it, the tool failed silently while the answer still looked fine.
- OpenTelemetry recorded 0 spans after the upgrade until I added `@ai-sdk/otel`, and the span names changed.
- Install size and import time are basically unchanged: 24.3 MB vs 23.8 MB and 115 ms vs 114 ms.

Related: my open-source [Next.js AI starter kit, Forgekit](https://www.fabwaseem.com/blog/nextjs-ai-starter-kit), already runs on AI SDK 7 (it uses `isStepCount`), so you can compare against a working v7 chat app.

## FAQ

### How do I upgrade from AI SDK 6 to AI SDK 7?

Use Node.js 22 or later, commit your code, install ai@7 and the v7 provider and UI packages, then run npx @ai-sdk/codemod v7. Fix the remaining TypeScript errors, review behaviour changes such as all-steps usage, per-step messages, onChunk and system messages, and install @ai-sdk/otel if you use OpenTelemetry.

### Does the AI SDK 7 codemod do the whole migration?

No. On my test app it fixed 15 lines of renames in 19.8 seconds, but only 1 of 9 failing tests. It can't change tool context to contextSchema and toolsContext, and it doesn't touch behaviour changes like usage now covering all steps.

### What are the breaking changes in AI SDK 7?

Node.js 22+ and ESM-only packages; system renamed to instructions; onFinish to onEnd; fullStream to stream; stepCountIs to isStepCount; results like usage and toolCalls accumulated across steps with old values on finalStep; per-tool context via toolsContext; system messages in messages rejected; and OpenTelemetry moved to @ai-sdk/otel.

### Why did my token usage double after upgrading to AI SDK 7?

In AI SDK 7, result.usage and the onEnd usage cover all steps of a tool loop, which is what totalUsage used to mean. In my two-step test it went from 15 to 30 tokens. Read result.finalStep.usage if you need only the last step.

### Why did my OpenTelemetry traces stop after upgrading to AI SDK 7?

OpenTelemetry support moved out of the ai package. Install @ai-sdk/otel and call registerTelemetry(new OpenTelemetry()) at startup, for example in instrumentation.ts. Span names also changed, from ai.generateText to names like invoke_agent and chat followed by the model id.

### Is AI SDK 7 ESM only? Can I still use require()?

The packages are ESM-only. On Node 24, require('ai') still worked in my test because Node can load ES modules with require(). On Node versions without that support, switch to import syntax and add "type": "module".

### How do I pass context to tools in AI SDK 7?

Add a contextSchema to the tool, read the typed context from the execute options, and pass values per tool with toolsContext, keyed by tool name. Shared data for prepareStep and events goes in runtimeContext. experimental_context no longer reaches tools.

### What is the migrate-ai-sdk-v6-to-v7 skill?

It's an agent skill from Vercel that you add with npx skills add vercel/ai --skill migrate-ai-sdk-v6-to-v7. It gives coding agents a migration checklist covering renames, tool context, finalStep and @ai-sdk/otel. Run the codemod first, then use the skill for behaviour changes and review the diff.


