# Migration Guide

> 

<note>

This is a living document for migrating from Nitro 2 to 3. Please check it regularly while using the beta version.

</note>

Nitro v3 introduces intentional backward-incompatible changes. This guide helps you migrate from Nitro v2.

## `nitropack` is renamed to `nitro`

The NPM package [nitropack](https://www.npmjs.com/package/nitropack) (v2) has been renamed to [nitro](https://www.npmjs.com/package/nitro) (v3).

**Migration:** Update the `nitropack` dependency to `nitro` in `package.json`:

<CodeGroup>

```diff [release channel]
{
  "dependencies": {
--    "nitropack": "latest"
++    "nitro": "latest"
  }
}
```

```diff [nightly channel]
{
  "dependencies": {
--    "nitropack": "latest"
++    "nitro": "npm:nitro-nightly"
  }
}
```

</CodeGroup>

**Migration:** Search your codebase and rename all instances of nitropack to nitro:

```diff
-- import { defineNitroConfig } from "nitropack/config"
++ import { defineConfig } from "nitro"
```

## nitro/runtime

Runtime utils had been moved to individual `nitro/*` subpath exports. Refer to docs for usage.

```diff
-- import { useStorage } from "nitropack/runtime/storage"
++ import { useStorage } from "nitro/storage"
```

## Minimum Supported Node.js Version: 20

Nitro now requires a minimum Node.js version of 20, as Node.js 18 reaches end-of-life in [April 2025](https://nodejs.org/en/about/previous-releases).

Please upgrade to the [latest LTS](https://nodejs.org/en/download) version (>= 20).

**Migration:**

- Check your local Node.js version using `node --version` and update if necessary.
- If you use a CI/CD system for deployment, ensure that your pipeline is running Node.js 20 or higher.
- If your hosting provider manages the Node.js runtime, make sure it's set to version 20, 22, or later.

## Type Imports

Nitro types are now only exported from `nitro/types`.

**Migration:** Import types from nitro/types instead of nitro:

```diff
-- import { NitroRuntimeConfig } from "nitropack"
++ import { NitroRuntimeConfig } from "nitro/types"
```

## App Config Support Removed

Nitro v2 supported a bundled app config that allowed defining configurations in `app.config.ts` and accessing them at runtime via `useAppConfig()`.

This feature had been removed.

**Migration:**

Use a regular `.ts` file in your server directory and import it directly.

## Preset updates

Nitro presets have been updated for the latest compatibility.

Some (legacy) presets have been removed or renamed.

<table>
<thead>
  <tr>
    <th>
      Old Preset
    </th>
    
    <th>
      New Preset
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        node
      </code>
    </td>
    
    <td>
      <code>
        node_middleware
      </code>
      
       (export changed to <code>
        middleware
      </code>
      
      )
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cloudflare
      </code>
      
      , <code>
        cloudflare_worker
      </code>
      
      , <code>
        cloudflare_module_legacy
      </code>
    </td>
    
    <td>
      <code>
        cloudflare_module
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        deno-server-legacy
      </code>
    </td>
    
    <td>
      <code>
        deno_server
      </code>
      
       with Deno v2
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        netlify-builder
      </code>
    </td>
    
    <td>
      <code>
        netlify
      </code>
      
       or <code>
        netlify_edge
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        vercel-edge
      </code>
    </td>
    
    <td>
      <code>
        vercel
      </code>
      
       with Fluid compute enabled
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        azure
      </code>
      
      , <code>
        azure_functions
      </code>
    </td>
    
    <td>
      <code>
        azure_swa
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        firebase
      </code>
    </td>
    
    <td>
      <code>
        firebase_app_hosting
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        iis
      </code>
    </td>
    
    <td>
      <code>
        iis_handler
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        deno
      </code>
    </td>
    
    <td>
      <code>
        deno_deploy
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        edgio
      </code>
    </td>
    
    <td>
      Discontinued
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli
      </code>
    </td>
    
    <td>
      Removed due to lack of use
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        service_worker
      </code>
    </td>
    
    <td>
      Removed due to instability
    </td>
  </tr>
</tbody>
</table>

## Cloudflare Bindings Access

In Nitro v2, Cloudflare environment variables and bindings were accessible via `event.context.cloudflare.env`.

In Nitro v3, the Cloudflare runtime context is attached to the request's runtime object instead.

**Migration:**

```diff
-- const { cloudflare } = event.context
-- const binding = cloudflare.env.MY_BINDING
++ const { env } = event.req.runtime.cloudflare
++ const binding = env.MY_BINDING
```

## Changed nitro subpath imports

Nitro v2 introduced multiple subpath exports, some of which have been removed or updated:

- `nitro/rollup`, `nitropack/core` (use `nitro/builder`)
- `nitropack/runtime/*` (use `nitro/*`)
- `nitropack/kit` (removed)
- `nitropack/presets` (removed)

An experimental `nitropack/kit` was introduced but has now been removed. A standalone Nitro Kit package may be introduced in the future with clearer objectives.

**Migration:**

- Use `NitroModule` from `nitro/types` instead of `defineNitroModule` from the kit.
- Prefer built-in Nitro presets (external presets are only for evaluation purposes).

## H3 v2

Nitro v3 upgrades to [H3 v2](https://h3.dev), which includes API changes. All H3 utilities are imported from `nitro/h3`.

### Web Standards

H3 v2 is rewritten based on web standard primitives ([`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL), [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers), [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)).

Access to `event.node.{req,res}` is only available in Node.js runtime. `event.web` is renamed to `event.req` (instance of web [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)).

### Response Handling

You should always explicitly **return** the response body or **throw** an error:

```diff
-- import { send, sendRedirect, sendStream } from "nitro/h3"
-- send(event, value)
-- sendStream(event, stream)
-- sendRedirect(event, location, code)
++ import { redirect } from "nitro/h3"
++ return value
++ return stream
++ return redirect(event, location, code)
```

Other changes:

- `sendError(event, error)` → `throw createError(error)`
- `sendNoContent(event)` → `return noContent(event)`
- `sendProxy(event, target)` → `return proxy(event, target)`

### Request Body

Most body utilities can be replaced with native `event.req` methods:

```diff
-- import { readBody, readRawBody, readFormData } from "nitro/h3"
++ // Use native Request methods
++ const json = await event.req.json()
++ const text = await event.req.text()
++ const formData = await event.req.formData()
++ const stream = event.req.body
```

### Headers

H3 now uses standard web [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers). Header values are always plain `string` (no `null`, `undefined`, or `string[]`).

```diff
-- import { getHeader, setHeader, getResponseStatus } from "nitro/h3"
-- getHeader(event, "x-foo")
-- setHeader(event, "x-foo", "bar")
++ event.req.headers.get("x-foo")
++ event.res.headers.set("x-foo", "bar")
++ event.res.status // instead of getResponseStatus(event)
```

### Handler Utils

```diff
-- import { eventHandler, defineEventHandler } from "nitro/h3"
++ import { defineHandler } from "nitro"
```

- `lazyEventHandler` → `defineLazyEventHandler`
- `useBase` → `withBase`

### Error Utils

```diff
-- import { createError, isError } from "nitro/h3"
++ import { HTTPError } from "nitro"
++ throw new HTTPError({ status: 404, message: "Not found" })
++ HTTPError.isError(error)
```

### Node.js Utils

```diff
-- import { defineNodeListener, fromNodeMiddleware, toNodeListener } from "nitro/h3"
++ import { defineNodeHandler, fromNodeHandler, toNodeHandler } from "nitro/h3"
```

## Optional Hooks

If you were using `useNitroApp().hooks` outside of Nitro plugins before, it might be undefined. Use new `useNitroHooks()` to guarantee having an instance.
