---
title: "Nuxt DevTools v4"
description: "Nuxt DevTools v4 is built on Devframe and Vite DevTools. It brings the full Vue DevTools and the wider devtools ecosystem to Nuxt."
canonical_url: "https://nuxt.com/blog/devtools-v4"
---
# Nuxt DevTools v4

> Nuxt DevTools v4 is built on Devframe and Vite DevTools. It brings the full Vue DevTools and the wider devtools ecosystem to Nuxt.

We are happy to announce [Nuxt DevTools v4](https://github.com/nuxt/devtools).

Nuxt DevTools v4 is built on top of [Devframe](https://github.com/devframes/devframe) and [Vite DevTools](https://github.com/vitejs/devtools). Because of this, Nuxt can now reuse the whole devtools ecosystem. We also no longer vendor Vue DevTools. You now get the full Vue DevTools, with all of its features.

::tip
Nuxt DevTools v4 ships with Nuxt v5. You can also use it with Nuxt v4.5+. See [Use it with Nuxt v4](#use-it-with-nuxt-v4).
::

You do not need to change anything in your app. Open the DevTools in the same way as before. The shortcut is `Shift + Option + D` (macOS) or `Shift + Alt + D` (Windows).

## Why We Rebuilt It

Since [v1.0](https://nuxt.com/blog/nuxt-devtools-v1-0), the Nuxt DevTools grew in a way that only worked for Nuxt. Each module that wanted a panel had to use our own API. Each feature from Vue DevTools had to be copied into our code. This was a lot of work for us, and it was hard to keep in sync.

We wanted to fix this at the root. The problem is not only about Nuxt. Every tool in the JavaScript world needs the same things: a panel, a way to talk to the server, and a way to show data. This has always been [our vision](https://devfra.me/posts/pluggable-extensible-playful-devtools) to provide a generalized, unified devtools experience for the ecosystem to share and build upon.

So we built Devframe, the framework-agnostic and agentic toolkit for devtools, and now Vite DevTools, Vue DevTools, and Nuxt DevTools all run on top of it.

## What Is Devframe

Devframe is a toolkit for building devtools, agnostic of any specific framework or tool. You describe a devtool once, with its panels, typed RPC, and shared state, and the same definition runs in any host: Nuxt, Vite, Next.js, a standalone CLI, a static report, or an MCP server for coding agents. Think of it as [`unplugin`](https://unplugin.unjs.io/) for devtools.

Under the hood, a devframe is exposed as a plain `Request` → `Response` handler, and a hub can compose many devframes behind one handler. You can learn more in the [Devframe repository](https://github.com/devframes/devframe) and [its announcement post](https://devfra.me/posts/pluggable-extensible-playful-devtools).

## One Ecosystem

With v4, Nuxt joins the same ecosystem as Vite and other tools. This works in two directions:

- Devtools that other tools build on Devframe or Vite DevTools can now work in your Nuxt app.
- Devtools that you build for Nuxt can now work outside of Nuxt.

![The Universal DevTools Ecosystem: general, build tool, framework-specific, and ecosystem devtools compose into each host](https://nuxt.com/assets/blog/devtools-v4/devtools-ecosystem.png)

The picture above shows how this composes for Nuxt. Most of what you see in the panel is not written for Nuxt at all. Tools like accessibility checks, terminals, and the data inspector are general, so every host gets them. Vite's own tools, like Vitest, Rolldown, and Oxlint, come with the build tool. Only the framework-specific layer, such as Vue's components and reactivity, Pinia, or Nuxt modules and auto imports, is specific to the framework. Community tools like UnoCSS or the ESLint Config Inspector plug in the same way.

::video
```yaml [props]
src: https://nuxt.com/assets/blog/devtools-v4/nuxt-devtools-compose.mp4
controls: true
autoplay: true
loop: true
muted: true
class: rounded-lg
```
::

Other hosts pick their own combination. A DevTools for Next.js or Svelte could reuse the same general and build tool layers, and only add its own framework-specific part. That means a new host starts with a rich set of tools, and every tool you write reaches more users.

You build a panel once, and many people can use it.

## The Full Vue DevTools and Vite DevTools

Thanks to Devframe, the latest Vue DevTools and Vite DevTools are now fully built on top of it. The stack has three layers, and each layer inherits and extends the one above:

- **Devframe Hub** is the foundation. It composes portable devframes behind one standard handler.
- **Vite DevTools** builds on the hub and adds the tools for the Vite toolchain, such as Vite plugins, Vitest, Rolldown, and Oxc.
- **Nuxt DevTools** builds on Vite DevTools and adds the Nuxt layer: Vue DevTools, Pinia, Nuxt modules, auto imports, and more.

![The Vite and Nuxt DevTools stack: Devframe Hub, Vite DevTools, and Nuxt DevTools, each layer inheriting from the previous one](https://nuxt.com/assets/blog/devtools-v4/nuxt-devtools-stack.png)

This is why we no longer need to vendor Vue DevTools. Instead of copying its features into our code, Nuxt DevTools inherits them, so you always get the complete and up-to-date Vue DevTools. Improvements to Vite DevTools reach Nuxt without extra work from us.

Under the hood, every devtool is a devframe that can run alone, join a hub, or mount into any host through the same standard handler. Vite DevTools is one host, and framework-specific hosts like Vue DevTools and Nuxt DevTools inherit and extend it.

![One devframe, many destinations: a single devframe definition can run standalone, join a hub, or mount into any host framework through the standard handler](https://nuxt.com/assets/blog/devtools-v4/devtools-inherit.png)

## A Transition Release

Regardless of the underlying architecture having undergone an overhaul and restructuring, the user-facing experience remains consistent, as we always aim to make progressive releases and make the migration smooth.

**Nuxt DevTools v4 is a transition release**.

We know that many modules use the previous Nuxt DevTools API from `@nuxt/devtools-kit`. If your module uses that API, it keeps working in v4. We added a shim that maps the old API to the new system. In development, the shim logs a warning so that you know which module to update.

## For Module Authors

The shim is only there to give you time. We recommend that you move your module to one of the new APIs:

- **Devframe**, if you want your panel to work in any tool: Nuxt, Vite, Next.js, a standalone CLI, or an MCP server.
- **Vite DevTools**, if your module only works with Vite and you want the smallest change. Nuxt DevTools v4 passes you the Vite DevTools context directly.

### Quick Migration

The old `@nuxt/devtools-kit` helpers map to the new context one by one. Each deprecated helper now logs a diagnostic code, so you can find the exact call to update:

| Before (`@nuxt/devtools-kit`) | After (`onDevtoolsReady`)                            | Warning        |
| ----------------------------- | ---------------------------------------------------- | -------------- |
| `addCustomTab()`              | `ctx.docks.register()`                               | `NDT_DEP_0005` |
| `refreshCustomTabs()`         | update the handle returned by `ctx.docks.register()` | `NDT_DEP_0006` |
| `extendServerRpc()`           | `ctx.scope('my-module').rpc.register()`              | `NDT_DEP_0003` |
| `startSubprocess()`           | `ctx.terminals.startChildProcess()`                  | `NDT_DEP_0004` |

Here is how a panel looks before and after the move to the Vite DevTools context:

```ts [Before]
import { addCustomTab, extendServerRpc } from '@nuxt/devtools-kit'

export default defineNuxtModule({
  setup() {
    addCustomTab({
      name: 'my-module',
      title: 'My Module',
      icon: 'carbon:apps',
      view: { type: 'iframe', src: '/__my-module/' },
    })

    extendServerRpc('my-module', {
      getModules: () => loadModules(),
    })
  },
})
```

```ts [After]
import { onDevtoolsReady } from '@nuxt/devtools-kit'

export default defineNuxtModule({
  setup() {
    onDevtoolsReady((ctx) => {
      ctx.docks.register({
        id: 'my-module',
        title: 'My Module',
        icon: 'carbon:apps',
        type: 'iframe',
        url: '/__my-module/',
      })

      ctx.scope('my-module').rpc.register({
        name: 'get-modules', // registered as `my-module:get-modules`
        type: 'query',
        handler: () => loadModules(),
      })
    })
  },
})
```

::note
The docks host does not cover `vnode` views and tab categories yet. If your module relies on them, keep using the shim for now.
::

::tip
Read more in the [module migration guide](https://devtools.nuxt.com/module/migration-v4).
::

### Go Portable with Devframe

If you want your tool to run beyond Nuxt, define it once with `defineDevframe()` and keep the Nuxt module as a thin wrapper. The RPC functions are typed, validated with any [Standard Schema](https://standardschema.dev/) library, and namespaced by your devframe id:

```ts [src/devframe.ts]
import { defineDevframe, defineRpcFunction } from 'devframe'
import * as v from 'valibot'

const getModules = defineRpcFunction({
  name: 'get-modules',
  type: 'query',
  args: [v.object({ limit: v.number() })],
  returns: v.array(v.object({ id: v.string(), size: v.number() })),
  handler: async ({ limit }) => (await loadModules()).slice(0, limit),
})

export default defineDevframe({
  id: 'my-tool',
  name: 'My Tool',
  icon: 'ph:gauge-duotone',
  clientAssets: 'client/dist',
  setup(ctx) {
    ctx.scope('my-tool').rpc.register(getModules)
  },
})
```

Then you can ship the same definition through whichever entry points suit your users:

```ts
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import { createBuild } from 'devframe/adapters/build'
import { createCac } from 'devframe/adapters/cac'
import { createMcpServer } from 'devframe/adapters/mcp'
import devframe from './devframe'

export const vitePlugin = createPluginFromDevframe(devframe) // Vite DevTools, and therefore Nuxt
export const runCli = () => createCac(devframe).parse() // standalone CLI
export const buildReport = () => createBuild(devframe, { outDir: 'dist-static' }) // static report
export const startMcp = () => createMcpServer(devframe, { transport: 'stdio' }) // for coding agents
```

If the UI of your tool is a Nuxt app, [`@devframes/nuxt/single`](https://github.com/devframes/devframe) wires it up as the browser side of a devframe and gives you a typed `$rpc` client in `useNuxtApp()`.

Head to the [Devframe documentation](https://github.com/devframes/devframe) to learn more, including a step-by-step tutorial that builds a data inspector from scratch.

## Give it a try

The easiest way to try Nuxt DevTools v4 is to [use Nuxt 5](https://nuxt.com/docs/5.x/getting-started/upgrade#migrating-to-nuxt-5), as it ships with DevTools v4 by default.

### Use It with Nuxt v4

If you are on Nuxt v4.5+ and want to try out Nuxt DevTools v4, you can do so by adding it as a module:

```bash
npx nuxt module add @nuxt/devtools@4
```

## Thank You

This release would not be possible without the people behind Devframe, Vite DevTools, and Vue DevTools.
Thank you to all the contributors who helped to build Devframe and to make these tools work together.

Please try the new Nuxt DevTools and let us know what you think. Feel free to open issues on [GitHub](https://github.com/nuxt/devtools/issues).

Happy debugging!


## Sitemap

See the full [sitemap](https://nuxt.com/sitemap.md) for all pages.
