{
  "type": "module",
  "source": "doc/api/best-practices-migrating-from-v7-to-v8.md",
  "modules": [
    {
      "textRaw": "Migrating from Undici 7 to 8",
      "name": "migrating_from_undici_7_to_8",
      "type": "module",
      "desc": "<p>This guide covers the changes you are most likely to hit when upgrading an\napplication or library from Undici v7 to v8.</p>",
      "modules": [
        {
          "textRaw": "Before you upgrade",
          "name": "before_you_upgrade",
          "type": "module",
          "desc": "<ul>\n<li>Make sure your runtime is Node.js <code>>= 22.19.0</code>.</li>\n<li>If you have custom dispatchers, interceptors, or handlers, review the\nhandler API changes before updating.</li>\n<li>If you rely on HTTP/1.1-only behavior, plan to set <code>allowH2: false</code>\nexplicitly.</li>\n</ul>",
          "displayName": "Before you upgrade"
        },
        {
          "textRaw": "1. Update your Node.js version",
          "name": "1._update_your_node.js_version",
          "type": "module",
          "desc": "<p>Undici v8 requires Node.js <code>>= 22.19.0</code>.</p>\n<p>If you are still on Node.js 20 or an older Node.js 22 release, upgrade Node.js\nfirst:</p>\n<pre><code class=\"language-bash\">node -v\n</code></pre>\n<p>If that command prints a version lower than <code>v22.19.0</code>, upgrade Node.js before\ninstalling Undici v8.</p>",
          "displayName": "1. Update your Node.js version"
        },
        {
          "textRaw": "2. Migrate custom dispatcher handlers to the v2 API",
          "name": "2._migrate_custom_dispatcher_handlers_to_the_v2_api",
          "type": "module",
          "desc": "<p>Undici v8 uses the newer dispatcher handler API consistently.</p>\n<p>If you implemented custom dispatchers, interceptors, or wrappers around\n<code>dispatch()</code>, update legacy callbacks such as <code>onConnect</code>, <code>onHeaders</code>, and\n<code>onComplete</code> to the newer callback names.</p>",
          "modules": [
            {
              "textRaw": "Old handler callbacks vs. v8 callbacks",
              "name": "old_handler_callbacks_vs._v8_callbacks",
              "type": "module",
              "desc": "<table>\n<thead>\n<tr>\n<th>Undici 7 style</th>\n<th>Undici 8 style</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>onConnect(abort, context)</code></td>\n<td><code>onRequestStart(controller, context)</code></td>\n</tr>\n<tr>\n<td><code>onHeaders(statusCode, rawHeaders, resume, statusText)</code></td>\n<td><code>onResponseStart(controller, statusCode, headers, statusText)</code></td>\n</tr>\n<tr>\n<td><code>onData(chunk)</code></td>\n<td><code>onResponseData(controller, chunk)</code></td>\n</tr>\n<tr>\n<td><code>onComplete(trailers)</code></td>\n<td><code>onResponseEnd(controller, trailers)</code></td>\n</tr>\n<tr>\n<td><code>onError(err)</code></td>\n<td><code>onResponseError(controller, err)</code></td>\n</tr>\n<tr>\n<td><code>onUpgrade(statusCode, rawHeaders, socket)</code></td>\n<td><code>onRequestUpgrade(controller, statusCode, headers, socket)</code></td>\n</tr>\n</tbody>\n</table>",
              "displayName": "Old handler callbacks vs. v8 callbacks"
            },
            {
              "textRaw": "Example",
              "name": "example",
              "type": "module",
              "desc": "<p>Before:</p>\n<pre><code class=\"language-js\">client.dispatch(options, {\n  onConnect (abort) {\n    this.abort = abort\n  },\n  onHeaders (statusCode, headers, resume) {\n    this.resume = resume\n    return true\n  },\n  onData (chunk) {\n    chunks.push(chunk)\n    return true\n  },\n  onComplete (trailers) {\n    console.log(trailers)\n  },\n  onError (err) {\n    console.error(err)\n  }\n})\n</code></pre>\n<p>After:</p>\n<pre><code class=\"language-js\">client.dispatch(options, {\n  onRequestStart (controller) {\n    this.controller = controller\n  },\n  onResponseStart (controller, statusCode, headers, statusText) {\n    console.log(statusCode, statusText, headers)\n  },\n  onResponseData (controller, chunk) {\n    chunks.push(chunk)\n  },\n  onResponseEnd (controller, trailers) {\n    console.log(trailers)\n  },\n  onResponseError (controller, err) {\n    console.error(err)\n  }\n})\n</code></pre>",
              "displayName": "Example"
            },
            {
              "textRaw": "Pause, resume, and abort now go through the controller",
              "name": "pause,_resume,_and_abort_now_go_through_the_controller",
              "type": "module",
              "desc": "<p>In Undici v7, legacy handlers could return <code>false</code> or keep references to\n<code>abort()</code> and <code>resume()</code> callbacks. In Undici v8, use the controller instead:</p>\n<pre><code class=\"language-js\">onRequestStart (controller) {\n  this.controller = controller\n}\n\nonResponseData (controller, chunk) {\n  controller.pause()\n  setImmediate(() => controller.resume())\n}\n\nonResponseError (controller, err) {\n  controller.abort(err)\n}\n</code></pre>",
              "displayName": "Pause, resume, and abort now go through the controller"
            },
            {
              "textRaw": "Raw headers and trailers moved to the controller",
              "name": "raw_headers_and_trailers_moved_to_the_controller",
              "type": "module",
              "desc": "<p>If you need the raw header arrays, read them from the controller:</p>\n<ul>\n<li><code>controller.rawHeaders</code></li>\n<li><code>controller.rawTrailers</code></li>\n</ul>",
              "displayName": "Raw headers and trailers moved to the controller"
            }
          ],
          "displayName": "2. Migrate custom dispatcher handlers to the v2 API"
        },
        {
          "textRaw": "3. Update `onBodySent()` handlers",
          "name": "3._update_`onbodysent()`_handlers",
          "type": "module",
          "desc": "<p>If you implemented <code>onBodySent()</code>, note that its signature changed.</p>\n<p>Before, handlers received counters:</p>\n<pre><code class=\"language-js\">onBodySent (chunkSize, totalBytesSent) {}\n</code></pre>\n<p>In Undici v8, handlers receive the actual chunk:</p>\n<pre><code class=\"language-js\">onBodySent (chunk) {}\n</code></pre>\n<p>If you need a notification that the whole body has been sent, use\n<code>onRequestSent()</code>:</p>\n<pre><code class=\"language-js\">onRequestSent () {\n  console.log('request body fully sent')\n}\n</code></pre>",
          "displayName": "3. Update `onBodySent()` handlers"
        },
        {
          "textRaw": "4. If you need HTTP/1.1 only, disable HTTP/2 explicitly",
          "name": "4._if_you_need_http/1.1_only,_disable_http/2_explicitly",
          "type": "module",
          "desc": "<p>Undici v8 enables HTTP/2 by default when a TLS server negotiates it via ALPN.</p>\n<p>If your application depends on HTTP/1.1-specific behavior, set <code>allowH2: false</code>\nexplicitly.</p>\n<p>Before:</p>\n<pre><code class=\"language-js\">const client = new Client('https://example.com')\n</code></pre>\n<p>After, to keep HTTP/1.1 only:</p>\n<pre><code class=\"language-js\">const client = new Client('https://example.com', {\n  allowH2: false\n})\n</code></pre>\n<p>The same applies when you configure an <code>Agent</code>:</p>\n<pre><code class=\"language-js\">const agent = new Agent({\n  allowH2: false\n})\n</code></pre>",
          "displayName": "4. If you need HTTP/1.1 only, disable HTTP/2 explicitly"
        },
        {
          "textRaw": "5. Use real `Blob` and `File` instances",
          "name": "5._use_real_`blob`_and_`file`_instances",
          "type": "module",
          "desc": "<p>Undici v8 no longer accepts fake Blob-like values that only imitate <code>Blob</code> or\n<code>File</code> via properties such as <code>Symbol.toStringTag</code>.</p>\n<p>If you were passing custom objects that looked like <code>Blob</code>s, replace them with\nactual <code>Blob</code> or <code>File</code> instances:</p>\n<pre><code class=\"language-js\">const body = new Blob(['hello'])\n</code></pre>",
          "displayName": "5. Use real `Blob` and `File` instances"
        },
        {
          "textRaw": "6. Avoid depending on the internal global dispatcher symbol",
          "name": "6._avoid_depending_on_the_internal_global_dispatcher_symbol",
          "type": "module",
          "desc": "<p><code>setGlobalDispatcher()</code> and <code>getGlobalDispatcher()</code> remain the public APIs and\nshould continue to be used.</p>\n<p>Internally, Undici v8 stores its dispatcher under\n<code>Symbol.for('undici.globalDispatcher.2')</code> and mirrors a v1-compatible wrapper\nfor legacy consumers such as Node.js built-in <code>fetch</code>.</p>\n<p>If your code was reading or writing <code>Symbol.for('undici.globalDispatcher.1')</code>\ndirectly, migrate to the public APIs instead:</p>\n<pre><code class=\"language-js\">import { setGlobalDispatcher, getGlobalDispatcher, Agent } from 'undici'\n\nsetGlobalDispatcher(new Agent())\nconst dispatcher = getGlobalDispatcher()\n</code></pre>\n<p>If you must expose a dispatcher to legacy v1 handler consumers, wrap it with\n<code>Dispatcher1Wrapper</code>:</p>\n<pre><code class=\"language-js\">import { Agent, Dispatcher1Wrapper } from 'undici'\n\nconst legacyCompatibleDispatcher = new Dispatcher1Wrapper(new Agent())\n</code></pre>",
          "displayName": "6. Avoid depending on the internal global dispatcher symbol"
        },
        {
          "textRaw": "7. Verify the upgrade",
          "name": "7._verify_the_upgrade",
          "type": "module",
          "desc": "<p>After moving to Undici v8, it is worth checking these paths in your test suite:</p>\n<ul>\n<li>requests that use a custom <code>dispatcher</code></li>\n<li><code>setGlobalDispatcher()</code> behavior</li>\n<li>any custom interceptor or retry handler</li>\n<li>uploads that use <code>Blob</code>, <code>File</code>, or <code>FormData</code></li>\n<li>integrations that depend on HTTP/1.1-only behavior</li>\n</ul>",
          "displayName": "7. Verify the upgrade"
        },
        {
          "textRaw": "Related documentation",
          "name": "related_documentation",
          "type": "module",
          "desc": "<ul>\n<li><a href=\"/docs/api/Dispatcher.html\">Dispatcher</a></li>\n<li><a href=\"/docs/api/Client.html\">Client</a></li>\n<li><a href=\"/docs/api/GlobalInstallation.html\">Global Installation</a></li>\n<li><a href=\"/docs/best-practices/undici-vs-builtin-fetch.html\">Undici Module vs. Node.js Built-in Fetch</a></li>\n</ul>",
          "displayName": "Related documentation"
        }
      ],
      "displayName": "Migrating from Undici 7 to 8"
    }
  ]
}