docs

Vue and Nuxt (Beta)

Beta. Buoy runs in Vue 3.3 and up, built with Vite. It runs in Nuxt 4 too. Buoy brings its own React for its own screens. Your app stays all Vue.

Start here

Let your coding agent install Buoy:

Let your coding agent install it
Read the prompt before you paste it
Install Buoy, the in-app devtools for React Native and Expo, in this project. Read the full instructions first: curl -fsSL https://buoy.gg/install.md Read the raw text, not a summary. If curl is unavailable, use any HTTP tool you have. Ask me to paste the document only if nothing can fetch it. Do the install yourself: inspect the repo, run the commands, edit the files. Do not hand me steps you can run. Work out the routine decisions from the repo: package manager, which app to target, where the menu mounts, which Buoy tools match the dependencies already installed. If Buoy is already partly installed, repair and extend it; never add a second mount, provider, or package set. When instructions conflict, follow this order: what I say here, then the document's rules about which packages exist and what needs my permission, then this project's own constraints, then the rest of the document, then your judgment. Ask me before: adding a native dependency, opening a browser or creating an account, changing what a production build does beyond what the document specifies, or anything hard to undo. Do not commit. You are not done when the packages install. Run this project's existing typecheck; add no tooling. Then report what you installed and why, what you skipped and why, every file you changed, what you verified, and the exact steps I take on the device to confirm the menu appears and captures a request.
The prompt asks your agent to inspect the project, choose matching tools and guide setup. Review its edits and verify the connection on your device.Read the setup instructions

To do it by hand, use these four steps. For Nuxt, skip to Nuxt.

1. Add Buoy

Run this in your app folder:

npm install --save-dev @buoy-gg/core @buoy-gg/vue @buoy-gg/network
sh
npm install --save-dev @buoy-gg/core @buoy-gg/vue @buoy-gg/network
npm install --save-dev @buoy-gg/core @buoy-gg/vue @buoy-gg/network

Add more tools the same way, such as @buoy-gg/storage. Keep all Buoy packages on the same release.

2. Add the Vite plugin

ts
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { buoy } from '@buoy-gg/core/vite';

export default defineConfig({
  plugins: [vue(), buoy()],
});
// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { buoy } from '@buoy-gg/core/vite';

export default defineConfig({
  plugins: [vue(), buoy()],
});

The plugin finds the tools you installed. It adds Buoy's early hook to index.html. It leaves Buoy out of prod builds.

3. Add the Buoy plugin

ts
// src/main.ts
import { createApp } from 'vue';
import { buoy } from '@buoy-gg/vue';

createApp(App)
  .use(pinia)
  .use(router)
  .use(VueQueryPlugin, { queryClient })
  .use(buoy)
  .mount('#app');
// src/main.ts
import { createApp } from 'vue';
import { buoy } from '@buoy-gg/vue';

createApp(App)
  .use(pinia)
  .use(router)
  .use(VueQueryPlugin, { queryClient })
  .use(buoy)
  .mount('#app');

It can go anywhere in the use chain. When your app mounts, it finds your router, Pinia and Vue Query client. It starts Buoy in dev builds. It stops Buoy when your app unmounts. It adds nothing to your page.

4. Sign in

sh
npx buoy login
npx buoy login

Sign in with a Free or Pro account. The CLI writes VITE_BUOY_KEY to a file that Git ignores. The Buoy plugin reads it for you, so you add no key to your code.

Run your app with npm run dev. Open Buoy's dial, then open Network. Make a web call in your app and check the list.

What works

ToolIn Vue
Network, Storage, ConsoleYes. They watch the browser itself.
RoutesYes. It shows route names and params from Vue Router.
QueryYes, with Vue Query. See below.
ZustandYes, for Pinia stores, Vue refs and vanilla Zustand stores.
HighlightYes. It boxes the components that rendered.
ReduxYes, for Redux Toolkit. Load @buoy-gg/redux/web before you make the store.
JotaiYes, for jotai/vanilla atoms. Pass them to watchAtoms.
Clock, Lifecycle, Location, PermissionsYes. They work in a plain browser.
Env, Events, Perf Monitor, Images, Impersonate, Time MachineYes.

Routes

Routes shows each page's name and params. Each page change shows up once, the first page too. The name is the route's name:

ts
{ path: '/pokemon/:id', name: 'Pokémon', component: Detail }
{ path: '/pokemon/:id', name: 'Pokémon', component: Detail }

A route with no name shows its path. The sitemap lists every route your router has. It updates when you add or remove routes. The Go button and the MCP navigate tool use Vue Router.

Vue Query

Install the Query tool and React Query too:

sh
npm install --save-dev @buoy-gg/react-query @tanstack/react-query
npm install --save-dev @buoy-gg/react-query @tanstack/react-query

Use the same version as your @tanstack/vue-query. Both must share one copy of @tanstack/query-core. The Buoy plugin finds your client from VueQueryPlugin. A custom queryClientKey works too.

Pinia

Your Pinia stores show up in Buoy's Zustand tool by themselves. Each one goes by its id. A store shows up the first time your app uses it. You can read and edit a store in the tool. An edit keeps the fields you did not change. Getters and actions are not shown.

To show a plain ref or reactive, pass it to the tool:

ts
import { buoyVueRef } from '@buoy-gg/vue/pinia';

app.use(buoy, {
  zustandStores: { count: buoyVueRef(count) },
});
import { buoyVueRef } from '@buoy-gg/vue/pinia';

app.use(buoy, {
  zustandStores: { count: buoyVueRef(count) },
});

A ref that holds one value shows up as { value }. Vanilla Zustand stores go in the same list as they are.

Highlight

Highlight boxes the components that rendered. It names each one by its component name. It skips Vue's own Transition, KeepAlive, Suspense and Teleport. It reads Vue's dev hook, so it works in dev builds.

It works next to Vue DevTools. That's the browser extension, vite-plugin-vue-devtools and Nuxt DevTools. Buoy shares Vue's dev hook with them, in any order.

Vue 3.6's Vapor components get no boxes yet. Your other components still do.

Keep your settings out of prod

Put app settings for Buoy in their own file. Load it with load, behind a dev check:

ts
app.use(buoy, {
  load: import.meta.env.DEV
    ? () => import('./buoy-settings').then((m) => m.settings)
    : undefined,
});
app.use(buoy, {
  load: import.meta.env.DEV
    ? () => import('./buoy-settings').then((m) => m.settings)
    : undefined,
});

The dev check lets the prod build drop that file.

QA builds

To keep Buoy in a QA build, set both of these:

ts
buoy({ enableInRelease: true })
buoy({ enableInRelease: true })
ts
app.use(buoy, { enableInRelease: true })
app.use(buoy, { enableInRelease: true })

The Vite plugin also keeps Vue's dev hook in that build, so Highlight still works. Account and plan rules still apply.

Nuxt

Install Buoy the same way, then add the module:

ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@buoy-gg/vue/nuxt'],
});
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@buoy-gg/vue/nuxt'],
});

That's all. You need no Vite plugin and no app.use. The module adds Buoy's early hook to Nuxt's browser entry. It starts Buoy in the browser, after Nuxt makes your app. The server build gets none of Buoy. Neither does a prod build.

Pass options with the buoy key:

ts
export default defineNuxtConfig({
  modules: ['@buoy-gg/vue/nuxt'],
  buoy: { options: { environment: 'qa' } },
});
export default defineNuxtConfig({
  modules: ['@buoy-gg/vue/nuxt'],
  buoy: { options: { environment: 'qa' } },
});

These options must be plain data. For options with functions, such as load, set setup: false. Then start Buoy in your own client plugin:

ts
// nuxt.config.ts
buoy: { setup: false },
// nuxt.config.ts
buoy: { setup: false },
ts
// app/plugins/buoy.client.ts
import { buoy } from '@buoy-gg/vue';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(buoy, { load });
});
// app/plugins/buoy.client.ts
import { buoy } from '@buoy-gg/vue';

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(buoy, { load });
});

@pinia/nuxt stores show up by themselves. Route names come from your page names. Nuxt names a page after its file, such as index.

Network shows the calls your app makes in the browser. A useFetch that runs on the server is not in the list. The browser gets its answer inside the page.

For a QA build, set buoy: { enableInRelease: true }.

Without the Vite plugin

The Buoy plugin still runs, but it loads no tools by itself. Pass them with modules. Put this line first in your entry file, before createApp:

ts
import '@buoy-gg/vue/register';
import '@buoy-gg/vue/register';

Your build must also drop Buoy from prod. Resolve the buoy-disabled export condition there.

TypeScript

The types in @buoy-gg/vue need no React types. Code that imports @buoy-gg/core or a tool's /web entry is different. Those types name React types your app does not have. Vue's own starter sets skipLibCheck: true, so it type-checks as it is. If yours doesn't, set it in tsconfig.json.