ai 6.0.30 → 6.0.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.mjs +1 -1
  4. package/dist/internal/index.js +1 -1
  5. package/dist/internal/index.mjs +1 -1
  6. package/docs/00-introduction/index.mdx +76 -0
  7. package/docs/02-foundations/01-overview.mdx +43 -0
  8. package/docs/02-foundations/02-providers-and-models.mdx +163 -0
  9. package/docs/02-foundations/03-prompts.mdx +620 -0
  10. package/docs/02-foundations/04-tools.mdx +160 -0
  11. package/docs/02-foundations/05-streaming.mdx +62 -0
  12. package/docs/02-foundations/index.mdx +43 -0
  13. package/docs/02-getting-started/00-choosing-a-provider.mdx +110 -0
  14. package/docs/02-getting-started/01-navigating-the-library.mdx +85 -0
  15. package/docs/02-getting-started/02-nextjs-app-router.mdx +556 -0
  16. package/docs/02-getting-started/03-nextjs-pages-router.mdx +542 -0
  17. package/docs/02-getting-started/04-svelte.mdx +627 -0
  18. package/docs/02-getting-started/05-nuxt.mdx +566 -0
  19. package/docs/02-getting-started/06-nodejs.mdx +512 -0
  20. package/docs/02-getting-started/07-expo.mdx +766 -0
  21. package/docs/02-getting-started/08-tanstack-start.mdx +583 -0
  22. package/docs/02-getting-started/index.mdx +44 -0
  23. package/docs/03-agents/01-overview.mdx +96 -0
  24. package/docs/03-agents/02-building-agents.mdx +367 -0
  25. package/docs/03-agents/03-workflows.mdx +370 -0
  26. package/docs/03-agents/04-loop-control.mdx +350 -0
  27. package/docs/03-agents/05-configuring-call-options.mdx +286 -0
  28. package/docs/03-agents/index.mdx +40 -0
  29. package/docs/03-ai-sdk-core/01-overview.mdx +33 -0
  30. package/docs/03-ai-sdk-core/05-generating-text.mdx +600 -0
  31. package/docs/03-ai-sdk-core/10-generating-structured-data.mdx +662 -0
  32. package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +1102 -0
  33. package/docs/03-ai-sdk-core/16-mcp-tools.mdx +375 -0
  34. package/docs/03-ai-sdk-core/20-prompt-engineering.mdx +144 -0
  35. package/docs/03-ai-sdk-core/25-settings.mdx +198 -0
  36. package/docs/03-ai-sdk-core/30-embeddings.mdx +247 -0
  37. package/docs/03-ai-sdk-core/31-reranking.mdx +218 -0
  38. package/docs/03-ai-sdk-core/35-image-generation.mdx +341 -0
  39. package/docs/03-ai-sdk-core/36-transcription.mdx +173 -0
  40. package/docs/03-ai-sdk-core/37-speech.mdx +167 -0
  41. package/docs/03-ai-sdk-core/40-middleware.mdx +480 -0
  42. package/docs/03-ai-sdk-core/45-provider-management.mdx +349 -0
  43. package/docs/03-ai-sdk-core/50-error-handling.mdx +149 -0
  44. package/docs/03-ai-sdk-core/55-testing.mdx +218 -0
  45. package/docs/03-ai-sdk-core/60-telemetry.mdx +313 -0
  46. package/docs/03-ai-sdk-core/65-devtools.mdx +107 -0
  47. package/docs/03-ai-sdk-core/index.mdx +88 -0
  48. package/docs/04-ai-sdk-ui/01-overview.mdx +44 -0
  49. package/docs/04-ai-sdk-ui/02-chatbot.mdx +1313 -0
  50. package/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx +535 -0
  51. package/docs/04-ai-sdk-ui/03-chatbot-resume-streams.mdx +263 -0
  52. package/docs/04-ai-sdk-ui/03-chatbot-tool-usage.mdx +682 -0
  53. package/docs/04-ai-sdk-ui/04-generative-user-interfaces.mdx +389 -0
  54. package/docs/04-ai-sdk-ui/05-completion.mdx +186 -0
  55. package/docs/04-ai-sdk-ui/08-object-generation.mdx +344 -0
  56. package/docs/04-ai-sdk-ui/20-streaming-data.mdx +397 -0
  57. package/docs/04-ai-sdk-ui/21-error-handling.mdx +190 -0
  58. package/docs/04-ai-sdk-ui/21-transport.mdx +174 -0
  59. package/docs/04-ai-sdk-ui/24-reading-ui-message-streams.mdx +104 -0
  60. package/docs/04-ai-sdk-ui/25-message-metadata.mdx +152 -0
  61. package/docs/04-ai-sdk-ui/50-stream-protocol.mdx +477 -0
  62. package/docs/04-ai-sdk-ui/index.mdx +64 -0
  63. package/docs/05-ai-sdk-rsc/01-overview.mdx +45 -0
  64. package/docs/05-ai-sdk-rsc/02-streaming-react-components.mdx +209 -0
  65. package/docs/05-ai-sdk-rsc/03-generative-ui-state.mdx +279 -0
  66. package/docs/05-ai-sdk-rsc/03-saving-and-restoring-states.mdx +105 -0
  67. package/docs/05-ai-sdk-rsc/04-multistep-interfaces.mdx +282 -0
  68. package/docs/05-ai-sdk-rsc/05-streaming-values.mdx +158 -0
  69. package/docs/05-ai-sdk-rsc/06-loading-state.mdx +273 -0
  70. package/docs/05-ai-sdk-rsc/08-error-handling.mdx +96 -0
  71. package/docs/05-ai-sdk-rsc/09-authentication.mdx +42 -0
  72. package/docs/05-ai-sdk-rsc/10-migrating-to-ui.mdx +722 -0
  73. package/docs/05-ai-sdk-rsc/index.mdx +58 -0
  74. package/docs/06-advanced/01-prompt-engineering.mdx +96 -0
  75. package/docs/06-advanced/02-stopping-streams.mdx +184 -0
  76. package/docs/06-advanced/03-backpressure.mdx +173 -0
  77. package/docs/06-advanced/04-caching.mdx +169 -0
  78. package/docs/06-advanced/05-multiple-streamables.mdx +68 -0
  79. package/docs/06-advanced/06-rate-limiting.mdx +60 -0
  80. package/docs/06-advanced/07-rendering-ui-with-language-models.mdx +213 -0
  81. package/docs/06-advanced/08-model-as-router.mdx +120 -0
  82. package/docs/06-advanced/09-multistep-interfaces.mdx +115 -0
  83. package/docs/06-advanced/09-sequential-generations.mdx +55 -0
  84. package/docs/06-advanced/10-vercel-deployment-guide.mdx +117 -0
  85. package/docs/06-advanced/index.mdx +11 -0
  86. package/docs/07-reference/01-ai-sdk-core/01-generate-text.mdx +2142 -0
  87. package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +3215 -0
  88. package/docs/07-reference/01-ai-sdk-core/03-generate-object.mdx +780 -0
  89. package/docs/07-reference/01-ai-sdk-core/04-stream-object.mdx +1140 -0
  90. package/docs/07-reference/01-ai-sdk-core/05-embed.mdx +190 -0
  91. package/docs/07-reference/01-ai-sdk-core/06-embed-many.mdx +171 -0
  92. package/docs/07-reference/01-ai-sdk-core/06-rerank.mdx +309 -0
  93. package/docs/07-reference/01-ai-sdk-core/10-generate-image.mdx +227 -0
  94. package/docs/07-reference/01-ai-sdk-core/11-transcribe.mdx +138 -0
  95. package/docs/07-reference/01-ai-sdk-core/12-generate-speech.mdx +214 -0
  96. package/docs/07-reference/01-ai-sdk-core/15-agent.mdx +203 -0
  97. package/docs/07-reference/01-ai-sdk-core/16-tool-loop-agent.mdx +449 -0
  98. package/docs/07-reference/01-ai-sdk-core/17-create-agent-ui-stream.mdx +148 -0
  99. package/docs/07-reference/01-ai-sdk-core/18-create-agent-ui-stream-response.mdx +168 -0
  100. package/docs/07-reference/01-ai-sdk-core/18-pipe-agent-ui-stream-to-response.mdx +144 -0
  101. package/docs/07-reference/01-ai-sdk-core/20-tool.mdx +196 -0
  102. package/docs/07-reference/01-ai-sdk-core/22-dynamic-tool.mdx +175 -0
  103. package/docs/07-reference/01-ai-sdk-core/23-create-mcp-client.mdx +410 -0
  104. package/docs/07-reference/01-ai-sdk-core/24-mcp-stdio-transport.mdx +68 -0
  105. package/docs/07-reference/01-ai-sdk-core/25-json-schema.mdx +94 -0
  106. package/docs/07-reference/01-ai-sdk-core/26-zod-schema.mdx +109 -0
  107. package/docs/07-reference/01-ai-sdk-core/27-valibot-schema.mdx +55 -0
  108. package/docs/07-reference/01-ai-sdk-core/28-output.mdx +342 -0
  109. package/docs/07-reference/01-ai-sdk-core/30-model-message.mdx +415 -0
  110. package/docs/07-reference/01-ai-sdk-core/31-ui-message.mdx +246 -0
  111. package/docs/07-reference/01-ai-sdk-core/32-validate-ui-messages.mdx +101 -0
  112. package/docs/07-reference/01-ai-sdk-core/33-safe-validate-ui-messages.mdx +113 -0
  113. package/docs/07-reference/01-ai-sdk-core/40-provider-registry.mdx +182 -0
  114. package/docs/07-reference/01-ai-sdk-core/42-custom-provider.mdx +121 -0
  115. package/docs/07-reference/01-ai-sdk-core/50-cosine-similarity.mdx +52 -0
  116. package/docs/07-reference/01-ai-sdk-core/60-wrap-language-model.mdx +59 -0
  117. package/docs/07-reference/01-ai-sdk-core/61-wrap-image-model.mdx +64 -0
  118. package/docs/07-reference/01-ai-sdk-core/65-language-model-v2-middleware.mdx +46 -0
  119. package/docs/07-reference/01-ai-sdk-core/66-extract-reasoning-middleware.mdx +68 -0
  120. package/docs/07-reference/01-ai-sdk-core/67-simulate-streaming-middleware.mdx +71 -0
  121. package/docs/07-reference/01-ai-sdk-core/68-default-settings-middleware.mdx +80 -0
  122. package/docs/07-reference/01-ai-sdk-core/69-add-tool-input-examples-middleware.mdx +155 -0
  123. package/docs/07-reference/01-ai-sdk-core/70-extract-json-middleware.mdx +147 -0
  124. package/docs/07-reference/01-ai-sdk-core/70-step-count-is.mdx +84 -0
  125. package/docs/07-reference/01-ai-sdk-core/71-has-tool-call.mdx +120 -0
  126. package/docs/07-reference/01-ai-sdk-core/75-simulate-readable-stream.mdx +94 -0
  127. package/docs/07-reference/01-ai-sdk-core/80-smooth-stream.mdx +145 -0
  128. package/docs/07-reference/01-ai-sdk-core/90-generate-id.mdx +43 -0
  129. package/docs/07-reference/01-ai-sdk-core/91-create-id-generator.mdx +89 -0
  130. package/docs/07-reference/01-ai-sdk-core/index.mdx +159 -0
  131. package/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +446 -0
  132. package/docs/07-reference/02-ai-sdk-ui/02-use-completion.mdx +179 -0
  133. package/docs/07-reference/02-ai-sdk-ui/03-use-object.mdx +178 -0
  134. package/docs/07-reference/02-ai-sdk-ui/31-convert-to-model-messages.mdx +230 -0
  135. package/docs/07-reference/02-ai-sdk-ui/32-prune-messages.mdx +108 -0
  136. package/docs/07-reference/02-ai-sdk-ui/40-create-ui-message-stream.mdx +151 -0
  137. package/docs/07-reference/02-ai-sdk-ui/41-create-ui-message-stream-response.mdx +113 -0
  138. package/docs/07-reference/02-ai-sdk-ui/42-pipe-ui-message-stream-to-response.mdx +73 -0
  139. package/docs/07-reference/02-ai-sdk-ui/43-read-ui-message-stream.mdx +57 -0
  140. package/docs/07-reference/02-ai-sdk-ui/46-infer-ui-tools.mdx +99 -0
  141. package/docs/07-reference/02-ai-sdk-ui/47-infer-ui-tool.mdx +75 -0
  142. package/docs/07-reference/02-ai-sdk-ui/50-direct-chat-transport.mdx +333 -0
  143. package/docs/07-reference/02-ai-sdk-ui/index.mdx +89 -0
  144. package/docs/07-reference/03-ai-sdk-rsc/01-stream-ui.mdx +767 -0
  145. package/docs/07-reference/03-ai-sdk-rsc/02-create-ai.mdx +90 -0
  146. package/docs/07-reference/03-ai-sdk-rsc/03-create-streamable-ui.mdx +91 -0
  147. package/docs/07-reference/03-ai-sdk-rsc/04-create-streamable-value.mdx +48 -0
  148. package/docs/07-reference/03-ai-sdk-rsc/05-read-streamable-value.mdx +78 -0
  149. package/docs/07-reference/03-ai-sdk-rsc/06-get-ai-state.mdx +50 -0
  150. package/docs/07-reference/03-ai-sdk-rsc/07-get-mutable-ai-state.mdx +70 -0
  151. package/docs/07-reference/03-ai-sdk-rsc/08-use-ai-state.mdx +26 -0
  152. package/docs/07-reference/03-ai-sdk-rsc/09-use-actions.mdx +42 -0
  153. package/docs/07-reference/03-ai-sdk-rsc/10-use-ui-state.mdx +35 -0
  154. package/docs/07-reference/03-ai-sdk-rsc/11-use-streamable-value.mdx +46 -0
  155. package/docs/07-reference/03-ai-sdk-rsc/20-render.mdx +262 -0
  156. package/docs/07-reference/03-ai-sdk-rsc/index.mdx +67 -0
  157. package/docs/07-reference/04-stream-helpers/01-ai-stream.mdx +89 -0
  158. package/docs/07-reference/04-stream-helpers/02-streaming-text-response.mdx +79 -0
  159. package/docs/07-reference/04-stream-helpers/05-stream-to-response.mdx +108 -0
  160. package/docs/07-reference/04-stream-helpers/07-openai-stream.mdx +77 -0
  161. package/docs/07-reference/04-stream-helpers/08-anthropic-stream.mdx +79 -0
  162. package/docs/07-reference/04-stream-helpers/09-aws-bedrock-stream.mdx +91 -0
  163. package/docs/07-reference/04-stream-helpers/10-aws-bedrock-anthropic-stream.mdx +96 -0
  164. package/docs/07-reference/04-stream-helpers/10-aws-bedrock-messages-stream.mdx +96 -0
  165. package/docs/07-reference/04-stream-helpers/11-aws-bedrock-cohere-stream.mdx +93 -0
  166. package/docs/07-reference/04-stream-helpers/12-aws-bedrock-llama-2-stream.mdx +93 -0
  167. package/docs/07-reference/04-stream-helpers/13-cohere-stream.mdx +78 -0
  168. package/docs/07-reference/04-stream-helpers/14-google-generative-ai-stream.mdx +85 -0
  169. package/docs/07-reference/04-stream-helpers/15-hugging-face-stream.mdx +84 -0
  170. package/docs/07-reference/04-stream-helpers/16-langchain-adapter.mdx +98 -0
  171. package/docs/07-reference/04-stream-helpers/16-llamaindex-adapter.mdx +70 -0
  172. package/docs/07-reference/04-stream-helpers/17-mistral-stream.mdx +81 -0
  173. package/docs/07-reference/04-stream-helpers/18-replicate-stream.mdx +83 -0
  174. package/docs/07-reference/04-stream-helpers/19-inkeep-stream.mdx +80 -0
  175. package/docs/07-reference/04-stream-helpers/index.mdx +103 -0
  176. package/docs/07-reference/05-ai-sdk-errors/ai-api-call-error.mdx +30 -0
  177. package/docs/07-reference/05-ai-sdk-errors/ai-download-error.mdx +27 -0
  178. package/docs/07-reference/05-ai-sdk-errors/ai-empty-response-body-error.mdx +24 -0
  179. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-argument-error.mdx +26 -0
  180. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-data-content-error.mdx +25 -0
  181. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-data-content.mdx +26 -0
  182. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-message-role-error.mdx +25 -0
  183. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-prompt-error.mdx +47 -0
  184. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-response-data-error.mdx +25 -0
  185. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-tool-approval-error.mdx +25 -0
  186. package/docs/07-reference/05-ai-sdk-errors/ai-invalid-tool-input-error.mdx +27 -0
  187. package/docs/07-reference/05-ai-sdk-errors/ai-json-parse-error.mdx +25 -0
  188. package/docs/07-reference/05-ai-sdk-errors/ai-load-api-key-error.mdx +24 -0
  189. package/docs/07-reference/05-ai-sdk-errors/ai-load-setting-error.mdx +24 -0
  190. package/docs/07-reference/05-ai-sdk-errors/ai-message-conversion-error.mdx +25 -0
  191. package/docs/07-reference/05-ai-sdk-errors/ai-no-content-generated-error.mdx +24 -0
  192. package/docs/07-reference/05-ai-sdk-errors/ai-no-image-generated-error.mdx +36 -0
  193. package/docs/07-reference/05-ai-sdk-errors/ai-no-object-generated-error.mdx +43 -0
  194. package/docs/07-reference/05-ai-sdk-errors/ai-no-speech-generated-error.mdx +25 -0
  195. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-model-error.mdx +26 -0
  196. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-provider-error.mdx +28 -0
  197. package/docs/07-reference/05-ai-sdk-errors/ai-no-such-tool-error.mdx +26 -0
  198. package/docs/07-reference/05-ai-sdk-errors/ai-no-transcript-generated-error.mdx +25 -0
  199. package/docs/07-reference/05-ai-sdk-errors/ai-retry-error.mdx +27 -0
  200. package/docs/07-reference/05-ai-sdk-errors/ai-too-many-embedding-values-for-call-error.mdx +27 -0
  201. package/docs/07-reference/05-ai-sdk-errors/ai-tool-call-not-found-for-approval-error.mdx +26 -0
  202. package/docs/07-reference/05-ai-sdk-errors/ai-tool-call-repair-error.mdx +28 -0
  203. package/docs/07-reference/05-ai-sdk-errors/ai-type-validation-error.mdx +25 -0
  204. package/docs/07-reference/05-ai-sdk-errors/ai-unsupported-functionality-error.mdx +25 -0
  205. package/docs/07-reference/05-ai-sdk-errors/index.mdx +38 -0
  206. package/docs/07-reference/index.mdx +34 -0
  207. package/docs/08-migration-guides/00-versioning.mdx +46 -0
  208. package/docs/08-migration-guides/24-migration-guide-6-0.mdx +823 -0
  209. package/docs/08-migration-guides/25-migration-guide-5-0-data.mdx +882 -0
  210. package/docs/08-migration-guides/26-migration-guide-5-0.mdx +3427 -0
  211. package/docs/08-migration-guides/27-migration-guide-4-2.mdx +99 -0
  212. package/docs/08-migration-guides/28-migration-guide-4-1.mdx +14 -0
  213. package/docs/08-migration-guides/29-migration-guide-4-0.mdx +1157 -0
  214. package/docs/08-migration-guides/36-migration-guide-3-4.mdx +14 -0
  215. package/docs/08-migration-guides/37-migration-guide-3-3.mdx +64 -0
  216. package/docs/08-migration-guides/38-migration-guide-3-2.mdx +46 -0
  217. package/docs/08-migration-guides/39-migration-guide-3-1.mdx +168 -0
  218. package/docs/08-migration-guides/index.mdx +22 -0
  219. package/docs/09-troubleshooting/01-azure-stream-slow.mdx +33 -0
  220. package/docs/09-troubleshooting/02-client-side-function-calls-not-invoked.mdx +22 -0
  221. package/docs/09-troubleshooting/03-server-actions-in-client-components.mdx +40 -0
  222. package/docs/09-troubleshooting/04-strange-stream-output.mdx +36 -0
  223. package/docs/09-troubleshooting/05-streamable-ui-errors.mdx +16 -0
  224. package/docs/09-troubleshooting/05-tool-invocation-missing-result.mdx +106 -0
  225. package/docs/09-troubleshooting/06-streaming-not-working-when-deployed.mdx +31 -0
  226. package/docs/09-troubleshooting/06-streaming-not-working-when-proxied.mdx +31 -0
  227. package/docs/09-troubleshooting/06-timeout-on-vercel.mdx +60 -0
  228. package/docs/09-troubleshooting/07-unclosed-streams.mdx +34 -0
  229. package/docs/09-troubleshooting/08-use-chat-failed-to-parse-stream.mdx +26 -0
  230. package/docs/09-troubleshooting/09-client-stream-error.mdx +25 -0
  231. package/docs/09-troubleshooting/10-use-chat-tools-no-response.mdx +32 -0
  232. package/docs/09-troubleshooting/11-use-chat-custom-request-options.mdx +149 -0
  233. package/docs/09-troubleshooting/12-typescript-performance-zod.mdx +46 -0
  234. package/docs/09-troubleshooting/12-use-chat-an-error-occurred.mdx +59 -0
  235. package/docs/09-troubleshooting/13-repeated-assistant-messages.mdx +73 -0
  236. package/docs/09-troubleshooting/14-stream-abort-handling.mdx +73 -0
  237. package/docs/09-troubleshooting/14-tool-calling-with-structured-outputs.mdx +48 -0
  238. package/docs/09-troubleshooting/15-abort-breaks-resumable-streams.mdx +55 -0
  239. package/docs/09-troubleshooting/15-stream-text-not-working.mdx +33 -0
  240. package/docs/09-troubleshooting/16-streaming-status-delay.mdx +63 -0
  241. package/docs/09-troubleshooting/17-use-chat-stale-body-data.mdx +141 -0
  242. package/docs/09-troubleshooting/18-ontoolcall-type-narrowing.mdx +66 -0
  243. package/docs/09-troubleshooting/19-unsupported-model-version.mdx +50 -0
  244. package/docs/09-troubleshooting/20-no-object-generated-content-filter.mdx +72 -0
  245. package/docs/09-troubleshooting/30-model-is-not-assignable-to-type.mdx +21 -0
  246. package/docs/09-troubleshooting/40-typescript-cannot-find-namespace-jsx.mdx +24 -0
  247. package/docs/09-troubleshooting/50-react-maximum-update-depth-exceeded.mdx +39 -0
  248. package/docs/09-troubleshooting/60-jest-cannot-find-module-ai-rsc.mdx +22 -0
  249. package/docs/09-troubleshooting/index.mdx +11 -0
  250. package/package.json +7 -3
@@ -0,0 +1,882 @@
1
+ ---
2
+ title: Migrate Your Data to AI SDK 5.0
3
+ description: Learn how to migrate your persisted messages and chat data from AI SDK 4.x to 5.0.
4
+ ---
5
+
6
+ # Migrate Your Data to AI SDK 5.0
7
+
8
+ AI SDK 5.0 introduces changes to the message structure and persistence patterns. Unlike code migrations that can often be automated with codemods, data migration depends on your specific persistence approach, database schema, and application requirements.
9
+
10
+ **This guide helps you get your application working with AI SDK 5.0 first** using a runtime conversion layer. This allows you to update your app immediately without database migrations blocking you. You can then migrate your data schema at your own pace.
11
+
12
+ ## Recommended Migration Process
13
+
14
+ Follow this two-phase approach for a safe migration:
15
+
16
+ ### Phase 1: Get Your App Working (Runtime Conversion)
17
+
18
+ **Goal:** Update your application to AI SDK 5.0 without touching your database.
19
+
20
+ 1. Update dependencies (install v4 types alongside v5)
21
+ 2. Add conversion functions to transform between v4 and v5 message formats
22
+ 3. Update data fetching logic to convert messages when reading from the database
23
+ 4. Update the rest of your application code to AI SDK 5.0 (see the [main migration guide](/docs/migration-guides/migration-guide-5-0))
24
+
25
+ Your database schema remains unchanged during Phase 1. You're only adding a conversion layer that transforms messages at runtime.
26
+
27
+ **Timeline:** Can be completed in hours or days.
28
+
29
+ ### Phase 2: Migrate to V5 Schema (Recommended)
30
+
31
+ **Goal:** Migrate your data to a v5-compatible schema, eliminating the runtime conversion overhead.
32
+
33
+ While Phase 1 gets you working immediately, migrate your schema soon after completing Phase 1. This phase uses a side-by-side migration approach with an equivalent v5 schema:
34
+
35
+ 1. Create `messages_v5` table alongside existing `messages` table
36
+ 2. Start dual-writing to both tables (with conversion)
37
+ 3. Run a background migration to convert existing messages
38
+ 4. Switch reads to the v5 schema
39
+ 5. Remove conversion from your route handlers
40
+ 6. Remove dual-write (write only to v5)
41
+ 7. Drop old tables
42
+
43
+ **Timeline:** Do this soon after Phase 1.
44
+
45
+ **Why this matters:**
46
+
47
+ - Removes runtime conversion overhead
48
+ - Eliminates technical debt early
49
+ - Type safety with v5 message format
50
+ - Easier to maintain and extend
51
+
52
+ ## Understanding the Changes
53
+
54
+ Before starting, understand the main persistence-related changes in AI SDK 5.0:
55
+
56
+ **AI SDK 4.0:**
57
+
58
+ - `content` field for text
59
+ - `reasoning` as a top-level property
60
+ - `toolInvocations` as a top-level property
61
+ - `parts` (optional) ordered array
62
+
63
+ **AI SDK 5.0:**
64
+
65
+ - `parts` array is the single source of truth
66
+ - `content` is removed (deprecated) and accessed via a `text` part
67
+ - `reasoning` is removed and replaced with a `reasoning` part
68
+ - `toolInvocations` is removed and replaced with `tool-${toolName}` parts with `input`/`output` (renamed from `args`/`result`)
69
+ - `data` role removed (use data parts instead)
70
+
71
+ ## Phase 1: Runtime Conversion Pattern
72
+
73
+ This creates a conversion layer without making changes to your database schema.
74
+
75
+ ### Step 1: Update Dependencies
76
+
77
+ To get proper TypeScript types for your v4 messages, install the v4 package alongside v5 using npm aliases:
78
+
79
+ ```json filename="package.json"
80
+ {
81
+ "dependencies": {
82
+ "ai": "^5.0.0",
83
+ "ai-legacy": "npm:ai@^4.3.2"
84
+ }
85
+ }
86
+ ```
87
+
88
+ Run:
89
+
90
+ ```bash
91
+ pnpm install
92
+ ```
93
+
94
+ Import v4 types for proper type safety:
95
+
96
+ ```tsx
97
+ import type { Message as V4Message } from 'ai-legacy';
98
+ import type { UIMessage } from 'ai';
99
+ ```
100
+
101
+ ### Step 2: Add Conversion Functions
102
+
103
+ Create type guards to detect which message format you're working with, and build a conversion function that handles all v4 message types:
104
+
105
+ ```tsx
106
+ import type {
107
+ ToolInvocation,
108
+ Message as V4Message,
109
+ UIMessage as LegacyUIMessage,
110
+ } from 'ai-legacy';
111
+ import type { ToolUIPart, UIMessage, UITools } from 'ai';
112
+
113
+ export type MyUIMessage = UIMessage<unknown, { custom: any }, UITools>;
114
+
115
+ type V4Part = NonNullable<V4Message['parts']>[number];
116
+ type V5Part = MyUIMessage['parts'][number];
117
+
118
+ // Type definitions for V4 parts
119
+ type V4ToolInvocationPart = Extract<V4Part, { type: 'tool-invocation' }>;
120
+
121
+ type V4ReasoningPart = Extract<V4Part, { type: 'reasoning' }>;
122
+
123
+ type V4SourcePart = Extract<V4Part, { type: 'source' }>;
124
+
125
+ type V4FilePart = Extract<V4Part, { type: 'file' }>;
126
+
127
+ // Type guards
128
+ function isV4Message(msg: V4Message | MyUIMessage): msg is V4Message {
129
+ return (
130
+ 'toolInvocations' in msg ||
131
+ (msg?.parts?.some(p => p.type === 'tool-invocation') ?? false) ||
132
+ msg?.role === 'data' ||
133
+ ('reasoning' in msg && typeof msg.reasoning === 'string') ||
134
+ (msg?.parts?.some(p => 'args' in p || 'result' in p) ?? false) ||
135
+ (msg?.parts?.some(p => 'reasoning' in p && 'details' in p) ?? false) ||
136
+ (msg?.parts?.some(
137
+ p => p.type === 'file' && 'mimeType' in p && 'data' in p,
138
+ ) ??
139
+ false)
140
+ );
141
+ }
142
+
143
+ function isV4ToolInvocationPart(part: unknown): part is V4ToolInvocationPart {
144
+ return (
145
+ typeof part === 'object' &&
146
+ part !== null &&
147
+ 'type' in part &&
148
+ part.type === 'tool-invocation' &&
149
+ 'toolInvocation' in part
150
+ );
151
+ }
152
+
153
+ function isV4ReasoningPart(part: unknown): part is V4ReasoningPart {
154
+ return (
155
+ typeof part === 'object' &&
156
+ part !== null &&
157
+ 'type' in part &&
158
+ part.type === 'reasoning' &&
159
+ 'reasoning' in part
160
+ );
161
+ }
162
+
163
+ function isV4SourcePart(part: unknown): part is V4SourcePart {
164
+ return (
165
+ typeof part === 'object' &&
166
+ part !== null &&
167
+ 'type' in part &&
168
+ part.type === 'source' &&
169
+ 'source' in part
170
+ );
171
+ }
172
+
173
+ function isV4FilePart(part: unknown): part is V4FilePart {
174
+ return (
175
+ typeof part === 'object' &&
176
+ part !== null &&
177
+ 'type' in part &&
178
+ part.type === 'file' &&
179
+ 'mimeType' in part &&
180
+ 'data' in part
181
+ );
182
+ }
183
+
184
+ // State mapping
185
+ const V4_TO_V5_STATE_MAP = {
186
+ 'partial-call': 'input-streaming',
187
+ call: 'input-available',
188
+ result: 'output-available',
189
+ } as const;
190
+
191
+ function convertToolInvocationState(
192
+ v4State: ToolInvocation['state'],
193
+ ): 'input-streaming' | 'input-available' | 'output-available' {
194
+ return V4_TO_V5_STATE_MAP[v4State] ?? 'output-available';
195
+ }
196
+
197
+ // Tool conversion
198
+ function convertV4ToolInvocationToV5ToolUIPart(
199
+ toolInvocation: ToolInvocation,
200
+ ): ToolUIPart {
201
+ return {
202
+ type: `tool-${toolInvocation.toolName}`,
203
+ toolCallId: toolInvocation.toolCallId,
204
+ input: toolInvocation.args,
205
+ output:
206
+ toolInvocation.state === 'result' ? toolInvocation.result : undefined,
207
+ state: convertToolInvocationState(toolInvocation.state),
208
+ };
209
+ }
210
+
211
+ // Part converters
212
+ function convertV4ToolInvocationPart(part: V4ToolInvocationPart): V5Part {
213
+ return convertV4ToolInvocationToV5ToolUIPart(part.toolInvocation);
214
+ }
215
+
216
+ function convertV4ReasoningPart(part: V4ReasoningPart): V5Part {
217
+ return { type: 'reasoning', text: part.reasoning };
218
+ }
219
+
220
+ function convertV4SourcePart(part: V4SourcePart): V5Part {
221
+ return {
222
+ type: 'source-url',
223
+ url: part.source.url,
224
+ sourceId: part.source.id,
225
+ title: part.source.title,
226
+ };
227
+ }
228
+
229
+ function convertV4FilePart(part: V4FilePart): V5Part {
230
+ return {
231
+ type: 'file',
232
+ mediaType: part.mimeType,
233
+ url: part.data,
234
+ };
235
+ }
236
+
237
+ function convertPart(part: V4Part | V5Part): V5Part {
238
+ if (isV4ToolInvocationPart(part)) {
239
+ return convertV4ToolInvocationPart(part);
240
+ }
241
+ if (isV4ReasoningPart(part)) {
242
+ return convertV4ReasoningPart(part);
243
+ }
244
+ if (isV4SourcePart(part)) {
245
+ return convertV4SourcePart(part);
246
+ }
247
+ if (isV4FilePart(part)) {
248
+ return convertV4FilePart(part);
249
+ }
250
+ // Already V5 format
251
+ return part;
252
+ }
253
+
254
+ // Message conversion
255
+ function createBaseMessage(
256
+ msg: V4Message | MyUIMessage,
257
+ index: number,
258
+ ): Pick<MyUIMessage, 'id' | 'role'> {
259
+ return {
260
+ id: msg.id || `msg-${index}`,
261
+ role: msg.role === 'data' ? 'assistant' : msg.role,
262
+ };
263
+ }
264
+
265
+ function convertDataMessage(msg: V4Message, index: number): MyUIMessage {
266
+ return {
267
+ ...createBaseMessage(msg, index),
268
+ parts: [
269
+ {
270
+ type: 'data-custom',
271
+ data: msg.data || msg.content,
272
+ },
273
+ ],
274
+ };
275
+ }
276
+
277
+ function buildPartsFromTopLevelFields(msg: V4Message): MyUIMessage['parts'] {
278
+ const parts: MyUIMessage['parts'] = [];
279
+
280
+ if (msg.reasoning) {
281
+ parts.push({ type: 'reasoning', text: msg.reasoning });
282
+ }
283
+
284
+ if (msg.toolInvocations) {
285
+ parts.push(
286
+ ...msg.toolInvocations.map(convertV4ToolInvocationToV5ToolUIPart),
287
+ );
288
+ }
289
+
290
+ if (msg.content && typeof msg.content === 'string') {
291
+ parts.push({ type: 'text', text: msg.content });
292
+ }
293
+
294
+ return parts;
295
+ }
296
+
297
+ function convertPartsArray(parts: V4Part[]): MyUIMessage['parts'] {
298
+ return parts.map(convertPart);
299
+ }
300
+
301
+ export function convertV4MessageToV5(
302
+ msg: V4Message | MyUIMessage,
303
+ index: number,
304
+ ): MyUIMessage {
305
+ if (!isV4Message(msg)) {
306
+ return msg as MyUIMessage;
307
+ }
308
+
309
+ if (msg.role === 'data') {
310
+ return convertDataMessage(msg, index);
311
+ }
312
+
313
+ const base = createBaseMessage(msg, index);
314
+ const parts = msg.parts
315
+ ? convertPartsArray(msg.parts)
316
+ : buildPartsFromTopLevelFields(msg);
317
+
318
+ return { ...base, parts };
319
+ }
320
+
321
+ // V5 to V4 conversion
322
+ function convertV5ToolUIPartToV4ToolInvocation(
323
+ part: ToolUIPart,
324
+ ): ToolInvocation {
325
+ const state =
326
+ part.state === 'input-streaming'
327
+ ? 'partial-call'
328
+ : part.state === 'input-available'
329
+ ? 'call'
330
+ : 'result';
331
+
332
+ const toolName = part.type.startsWith('tool-')
333
+ ? part.type.slice(5)
334
+ : part.type;
335
+
336
+ const base = {
337
+ toolCallId: part.toolCallId,
338
+ toolName,
339
+ args: part.input,
340
+ state,
341
+ };
342
+
343
+ if (state === 'result' && part.output !== undefined) {
344
+ return { ...base, state: 'result' as const, result: part.output };
345
+ }
346
+
347
+ return base as ToolInvocation;
348
+ }
349
+
350
+ export function convertV5MessageToV4(msg: MyUIMessage): LegacyUIMessage {
351
+ const parts: V4Part[] = [];
352
+
353
+ const base: LegacyUIMessage = {
354
+ id: msg.id,
355
+ role: msg.role,
356
+ content: '',
357
+ parts,
358
+ };
359
+
360
+ let textContent = '';
361
+ let reasoning: string | undefined;
362
+ const toolInvocations: ToolInvocation[] = [];
363
+
364
+ for (const part of msg.parts) {
365
+ if (part.type === 'text') {
366
+ textContent = part.text;
367
+ parts.push({ type: 'text', text: part.text });
368
+ } else if (part.type === 'reasoning') {
369
+ reasoning = part.text;
370
+ parts.push({
371
+ type: 'reasoning',
372
+ reasoning: part.text,
373
+ details: [{ type: 'text', text: part.text }],
374
+ });
375
+ } else if (part.type.startsWith('tool-')) {
376
+ const toolInvocation = convertV5ToolUIPartToV4ToolInvocation(
377
+ part as ToolUIPart,
378
+ );
379
+ parts.push({ type: 'tool-invocation', toolInvocation: toolInvocation });
380
+ toolInvocations.push(toolInvocation);
381
+ } else if (part.type === 'source-url') {
382
+ parts.push({
383
+ type: 'source',
384
+ source: {
385
+ id: part.sourceId,
386
+ url: part.url,
387
+ title: part.title,
388
+ sourceType: 'url',
389
+ },
390
+ });
391
+ } else if (part.type === 'file') {
392
+ parts.push({
393
+ type: 'file',
394
+ mimeType: part.mediaType,
395
+ data: part.url,
396
+ });
397
+ } else if (part.type === 'data-custom') {
398
+ base.data = part.data;
399
+ }
400
+ }
401
+
402
+ if (textContent) {
403
+ base.content = textContent;
404
+ }
405
+
406
+ if (reasoning) {
407
+ base.reasoning = reasoning;
408
+ }
409
+
410
+ if (toolInvocations.length > 0) {
411
+ base.toolInvocations = toolInvocations;
412
+ }
413
+
414
+ if (parts.length > 0) {
415
+ base.parts = parts;
416
+ }
417
+ return base;
418
+ }
419
+ ```
420
+
421
+ ### Step 3: Convert Messages When Reading
422
+
423
+ Apply the conversion when loading messages from your database:
424
+
425
+ <Note type="warning">Adapt this code to your specific database and ORM.</Note>
426
+
427
+ ```tsx
428
+ import { convertV4MessageToV5, type MyUIMessage } from './conversion';
429
+
430
+ export async function loadChat(chatId: string): Promise<MyUIMessage[]> {
431
+ // Fetch messages from your database (pseudocode - update based on your data access layer)
432
+ const rawMessages = await db
433
+ .select()
434
+ .from(messages)
435
+ .where(eq(messages.chatId, chatId))
436
+ .orderBy(messages.createdAt);
437
+
438
+ // Convert on read
439
+ return rawMessages.map((msg, index) => convertV4MessageToV5(msg, index));
440
+ }
441
+ ```
442
+
443
+ ### Step 4: Convert Messages When Saving
444
+
445
+ In Phase 1, your application runs on v5 but your database stores v4 format. Convert messages inline in your route handlers before passing them to your database functions:
446
+
447
+ ```tsx
448
+ import {
449
+ convertV5MessageToV4,
450
+ convertV4MessageToV5,
451
+ type MyUIMessage,
452
+ } from './conversion';
453
+ import { upsertMessage, loadChat } from './db/actions';
454
+ import { streamText, generateId, convertToModelMessages } from 'ai';
455
+ __PROVIDER_IMPORT__;
456
+
457
+ export async function POST(req: Request) {
458
+ const { message, chatId }: { message: MyUIMessage; chatId: string } =
459
+ await req.json();
460
+
461
+ // Convert and save incoming user message (v5 to v4 inline)
462
+ await upsertMessage({
463
+ chatId,
464
+ id: message.id,
465
+ message: convertV5MessageToV4(message), // convert to v4
466
+ });
467
+
468
+ // Load previous messages (already in v5 format)
469
+ const previousMessages = await loadChat(chatId);
470
+ const messages = [...previousMessages, message];
471
+
472
+ const result = streamText({
473
+ model: __MODEL__,
474
+ messages: convertToModelMessages(messages),
475
+ tools: {
476
+ // Your tools here
477
+ },
478
+ });
479
+
480
+ return result.toUIMessageStreamResponse({
481
+ generateMessageId: generateId,
482
+ originalMessages: messages,
483
+ onFinish: async ({ responseMessage }) => {
484
+ // Convert and save assistant response (v5 to v4 inline)
485
+ await upsertMessage({
486
+ chatId,
487
+ id: responseMessage.id,
488
+ message: convertV5MessageToV4(responseMessage),
489
+ });
490
+ },
491
+ });
492
+ }
493
+ ```
494
+
495
+ Keep your `upsertMessage` (or equivalent) function unchanged to continue working with v4 messages.
496
+
497
+ With Steps 3 and 4 complete, you have a bidirectional conversion layer:
498
+
499
+ - **Reading:** v4 (database) → v5 (application)
500
+ - **Writing:** v5 (application) → v4 (database)
501
+
502
+ Your database schema remains unchanged, but your application now works with v5 format.
503
+
504
+ **What's next:** Follow the main migration guide to update the rest of your application code to AI SDK 5.0, including API routes, components, and other code that uses the AI SDK. Then proceed to Phase 2.
505
+
506
+ See the [main migration guide](/docs/migration-guides/migration-guide-5-0) for details.
507
+
508
+ ## Phase 2: Side-by-Side Schema Migration
509
+
510
+ Now that your application is updated to AI SDK 5.0 and working with the runtime conversion layer from Phase 1, you have a fully functional system. However, **the conversion functions are only a temporary solution**. Your database still stores messages in the v4 format, which means:
511
+
512
+ - Every read operation requires runtime conversion overhead
513
+ - You maintain backward compatibility code indefinitely
514
+ - Future features require working with the legacy schema
515
+
516
+ **Phase 2 migrates your message history to the v5 schema**, eliminating the conversion layer and enabling better performance and long-term maintainability.
517
+
518
+ This phase uses a simplified approach: create a new `messages_v5` table with the same structure as your current `messages` table, but storing v5-formatted message parts.
519
+
520
+ <Note type="warning">
521
+ **Adapt phase 2 examples to your setup**
522
+
523
+ These code examples demonstrate migration patterns. Your implementation will differ based on your database (Postgres, MySQL, SQLite), ORM (Drizzle, Prisma, raw SQL), schema design, and data persistence patterns.
524
+
525
+ Use these examples as a guide, then adapt them to your specific setup.
526
+
527
+ </Note>
528
+
529
+ ### Overview: Migration Strategy
530
+
531
+ 1. **Create `messages_v5` table** alongside existing `messages` table
532
+ 2. **Dual-write** new messages to both schemas (with conversion)
533
+ 3. **Background migration** to convert existing messages
534
+ 4. **Verify** data integrity
535
+ 5. **Update read functions** to use `messages_v5` schema
536
+ 6. **Remove conversion** from route handlers
537
+ 7. **Remove dual-write** (write only to `messages_v5`)
538
+ 8. **Clean up** old tables
539
+
540
+ This ensures your application keeps running throughout the migration with no data loss risk.
541
+
542
+ ### Step 1: Create V5 Schema Alongside V4
543
+
544
+ Create a new `messages_v5` table with the same structure as your existing table, but designed to store v5 message parts:
545
+
546
+ **Existing v4 Schema (keep running):**
547
+
548
+ ```typescript
549
+ import { UIMessage } from 'ai-legacy';
550
+
551
+ export const messages = pgTable('messages', {
552
+ id: varchar()
553
+ .primaryKey()
554
+ .$defaultFn(() => nanoid()),
555
+ chatId: varchar()
556
+ .references(() => chats.id, { onDelete: 'cascade' })
557
+ .notNull(),
558
+ createdAt: timestamp().defaultNow().notNull(),
559
+ parts: jsonb().$type<UIMessage['parts']>().notNull(),
560
+ role: text().$type<UIMessage['role']>().notNull(),
561
+ });
562
+ ```
563
+
564
+ **New v5 Schema (create alongside):**
565
+
566
+ ```typescript
567
+ import { MyUIMessage } from './conversion';
568
+
569
+ export const messages_v5 = pgTable('messages_v5', {
570
+ id: varchar()
571
+ .primaryKey()
572
+ .$defaultFn(() => nanoid()),
573
+ chatId: varchar()
574
+ .references(() => chats.id, { onDelete: 'cascade' })
575
+ .notNull(),
576
+ createdAt: timestamp().defaultNow().notNull(),
577
+ parts: jsonb().$type<MyUIMessage['parts']>().notNull(),
578
+ role: text().$type<MyUIMessage['role']>().notNull(),
579
+ });
580
+ ```
581
+
582
+ Run your migration to create the new table:
583
+
584
+ ```bash
585
+ pnpm drizzle-kit generate
586
+ pnpm drizzle-kit migrate
587
+ ```
588
+
589
+ ### Step 2: Implement Dual-Write for New Messages
590
+
591
+ Update your save functions to write to both schemas during the migration period. This ensures new messages are available in both formats:
592
+
593
+ ```typescript
594
+ import { convertV4MessageToV5 } from './conversion';
595
+ import { messages, messages_v5 } from './schema';
596
+ import type { UIMessage } from 'ai-legacy';
597
+
598
+ export const upsertMessage = async ({
599
+ chatId,
600
+ message,
601
+ id,
602
+ }: {
603
+ id: string;
604
+ chatId: string;
605
+ message: UIMessage; // Still accepts v4 format
606
+ }) => {
607
+ return await db.transaction(async tx => {
608
+ // Write to v4 schema (existing)
609
+ const [result] = await tx
610
+ .insert(messages)
611
+ .values({
612
+ chatId,
613
+ parts: message.parts ?? [],
614
+ role: message.role,
615
+ id,
616
+ })
617
+ .onConflictDoUpdate({
618
+ target: messages.id,
619
+ set: {
620
+ parts: message.parts ?? [],
621
+ chatId,
622
+ },
623
+ })
624
+ .returning();
625
+
626
+ // Convert and write to v5 schema (new)
627
+ const v5Message = convertV4MessageToV5(
628
+ {
629
+ ...message,
630
+ content: '',
631
+ },
632
+ 0,
633
+ );
634
+
635
+ await tx
636
+ .insert(messages_v5)
637
+ .values({
638
+ chatId,
639
+ parts: v5Message.parts ?? [],
640
+ role: v5Message.role,
641
+ id,
642
+ })
643
+ .onConflictDoUpdate({
644
+ target: messages_v5.id,
645
+ set: {
646
+ parts: v5Message.parts ?? [],
647
+ chatId,
648
+ },
649
+ });
650
+
651
+ return result;
652
+ });
653
+ };
654
+ ```
655
+
656
+ ### Step 3: Migrate Existing Messages
657
+
658
+ Create a script to migrate existing messages from v4 to v5 schema:
659
+
660
+ ```typescript
661
+ import { convertV4MessageToV5 } from './conversion';
662
+ import { db } from './db';
663
+ import { messages, messages_v5 } from './db/schema';
664
+
665
+ async function migrateExistingMessages() {
666
+ console.log('Starting migration of existing messages...');
667
+
668
+ // Get all v4 messages that haven't been migrated yet
669
+ const migratedIds = await db.select({ id: messages_v5.id }).from(messages_v5);
670
+
671
+ const migratedIdSet = new Set(migratedIds.map(m => m.id));
672
+
673
+ const allMessages = await db.select().from(messages);
674
+ const unmigrated = allMessages.filter(msg => !migratedIdSet.has(msg.id));
675
+
676
+ console.log(`Found ${unmigrated.length} messages to migrate`);
677
+
678
+ let migrated = 0;
679
+ let errors = 0;
680
+ const batchSize = 100;
681
+
682
+ for (let i = 0; i < unmigrated.length; i += batchSize) {
683
+ const batch = unmigrated.slice(i, i + batchSize);
684
+
685
+ await db.transaction(async tx => {
686
+ for (const msg of batch) {
687
+ try {
688
+ // Convert message to v5 format
689
+ const v5Message = convertV4MessageToV5(
690
+ {
691
+ id: msg.id,
692
+ content: '',
693
+ role: msg.role,
694
+ parts: msg.parts,
695
+ createdAt: msg.createdAt,
696
+ },
697
+ 0,
698
+ );
699
+
700
+ // Insert into v5 messages table
701
+ await tx.insert(messages_v5).values({
702
+ id: v5Message.id,
703
+ chatId: msg.chatId,
704
+ role: v5Message.role,
705
+ parts: v5Message.parts,
706
+ createdAt: msg.createdAt,
707
+ });
708
+
709
+ migrated++;
710
+ } catch (error) {
711
+ console.error(`Error migrating message ${msg.id}:`, error);
712
+ errors++;
713
+ }
714
+ }
715
+ });
716
+
717
+ console.log(`Progress: ${migrated}/${unmigrated.length} messages migrated`);
718
+ }
719
+
720
+ console.log(`Migration complete: ${migrated} migrated, ${errors} errors`);
721
+ }
722
+
723
+ // Run migration
724
+ migrateExistingMessages().catch(console.error);
725
+ ```
726
+
727
+ This script:
728
+
729
+ - Only migrates messages that haven't been migrated yet
730
+ - Uses batching for better performance
731
+ - Can be run multiple times safely
732
+ - Can be stopped and resumed
733
+
734
+ ### Step 4: Verify Migration
735
+
736
+ Create a verification script to ensure data integrity:
737
+
738
+ ```typescript
739
+ import { count } from 'drizzle-orm';
740
+ import { db } from './db';
741
+ import { messages, messages_v5 } from './db/schema';
742
+
743
+ async function verifyMigration() {
744
+ // Count messages in both schemas
745
+ const v4Count = await db.select({ count: count() }).from(messages);
746
+ const v5Count = await db.select({ count: count() }).from(messages_v5);
747
+
748
+ console.log('Migration Status:');
749
+ console.log(`V4 Messages: ${v4Count[0].count}`);
750
+ console.log(`V5 Messages: ${v5Count[0].count}`);
751
+ console.log(
752
+ `Migration progress: ${((v5Count[0].count / v4Count[0].count) * 100).toFixed(2)}%`,
753
+ );
754
+ }
755
+
756
+ verifyMigration().catch(console.error);
757
+ ```
758
+
759
+ ### Step 5: Read from V5 Schema
760
+
761
+ Once migration is complete, update your read functions to use the new v5 schema. Since the data is now in v5 format, you don't need conversion:
762
+
763
+ ```typescript
764
+ import type { MyUIMessage } from './conversion';
765
+
766
+ export const loadChat = async (chatId: string): Promise<MyUIMessage[]> => {
767
+ // Load from v5 schema - no conversion needed
768
+ const messages = await db
769
+ .select()
770
+ .from(messages_v5)
771
+ .where(eq(messages_v5.chatId, chatId))
772
+ .orderBy(messages_v5.createdAt);
773
+
774
+ return messages;
775
+ };
776
+ ```
777
+
778
+ ### Step 6: Write to V5 Schema Only
779
+
780
+ Once your read functions work with v5 and your background migration is complete, stop dual-writing and only write to v5:
781
+
782
+ ```typescript
783
+ import type { MyUIMessage } from './conversion';
784
+
785
+ export const upsertMessage = async ({
786
+ chatId,
787
+ message,
788
+ id,
789
+ }: {
790
+ id: string;
791
+ chatId: string;
792
+ message: MyUIMessage; // Now accepts v5 format
793
+ }) => {
794
+ // Write to v5 schema only
795
+ const [result] = await db
796
+ .insert(messages_v5)
797
+ .values({
798
+ chatId,
799
+ parts: message.parts ?? [],
800
+ role: message.role,
801
+ id,
802
+ })
803
+ .onConflictDoUpdate({
804
+ target: messages_v5.id,
805
+ set: {
806
+ parts: message.parts ?? [],
807
+ chatId,
808
+ },
809
+ })
810
+ .returning();
811
+
812
+ return result;
813
+ };
814
+ ```
815
+
816
+ Update your route handler to pass v5 messages directly:
817
+
818
+ ```tsx
819
+ export async function POST(req: Request) {
820
+ const { message, chatId }: { message: MyUIMessage; chatId: string } =
821
+ await req.json();
822
+
823
+ // Pass v5 message directly - no conversion needed
824
+ await upsertMessage({
825
+ chatId,
826
+ id: message.id,
827
+ message,
828
+ });
829
+
830
+ const previousMessages = await loadChat(chatId);
831
+ const messages = [...previousMessages, message];
832
+
833
+ const result = streamText({
834
+ model: __MODEL__,
835
+ messages: convertToModelMessages(messages),
836
+ tools: {
837
+ // Your tools here
838
+ },
839
+ });
840
+
841
+ return result.toUIMessageStreamResponse({
842
+ generateMessageId: generateId,
843
+ originalMessages: messages,
844
+ onFinish: async ({ responseMessage }) => {
845
+ await upsertMessage({
846
+ chatId,
847
+ id: responseMessage.id,
848
+ message: responseMessage, // No conversion needed
849
+ });
850
+ },
851
+ });
852
+ }
853
+ ```
854
+
855
+ ### Step 7: Complete the Switch
856
+
857
+ Once verification passes and you're confident in the migration:
858
+
859
+ 1. **Remove conversion functions**: Delete the v4↔v5 conversion utilities
860
+ 2. **Remove `ai-legacy` dependency**: Uninstall the v4 types package
861
+ 3. **Test thoroughly**: Ensure your application works correctly with v5 schema
862
+ 4. **Monitor**: Watch for issues in production
863
+ 5. **Clean up**: After a safe period (1-2 weeks), drop the old table
864
+
865
+ ```sql
866
+ -- After confirming everything works
867
+ DROP TABLE messages;
868
+
869
+ -- Optionally rename v5 table to standard name
870
+ ALTER TABLE messages_v5 RENAME TO messages;
871
+ ```
872
+
873
+ **Phase 2 is now complete.** Your application is fully migrated to v5 schema with no runtime conversion overhead.
874
+
875
+ ## Community Resources
876
+
877
+ The following community members have shared their migration experiences:
878
+
879
+ - [AI SDK Migration: Handling Previously Saved Messages](https://jhakim.com/blog/ai-sdk-migration-handling-previously-saved-messages) - Detailed transformation function implementation
880
+ - [How we migrated Atypica.ai to AI SDK v5 without breaking 10M+ chat histories](https://blog.web3nomad.com/p/how-we-migrated-atypicaai-to-ai-sdk-v5-without-breaking-10m-chat-histories) - Runtime conversion approach for large-scale migration
881
+
882
+ For more API change details, see the [main migration guide](/docs/migration-guides/migration-guide-5-0).