---
title: "v1 to v2"
description: "Migration guide for upgrading from Nuxt Scripts v1.x to v2.0."
canonical_url: "https://scripts.nuxt.com/docs/migration-guide/v1-to-v2"
last_updated: "2026-10-11T11:20:16.517Z"
---

Nuxt Scripts 2 moves script ownership and SDK readiness onto the lifecycle APIs
introduced in Unhead 3.3.1. This removes component callbacks and trigger listeners
as soon as their consumer unmounts, without tearing down a script still used by
other components.

## Requirements

| Dependency                    | Required version                              |
| ----------------------------- | --------------------------------------------- |
| [Node.js](https://nodejs.org) | `^22.22.3 \|\| ^24.15.0 \|\| >=26.0.0`        |
| Nuxt                          | `^4.6.0 \|\| ^5.0.0`, with Nitro 2 or Nitro 3 |
| `@unhead/vue`                 | `^3.4.2`                                      |
| `unhead`                      | `^3.4.2`                                      |

Upgrade Nuxt and refresh its locked dependencies before installing v2:

```bash
npx nuxi@latest upgrade --force
```

Run the dedicated migration CLI from the project root. Preview its changes first
if the project has dynamic Nuxt configuration:

```bash
npx @nuxt/scripts-cli migrate v2 --dry-run
npx @nuxt/scripts-cli migrate v2
```

The CLI handles static registry configuration and mechanical API renames. It
lists dynamic configuration and removed components that need manual follow-up.

The module now stops setup with an actionable error when either Unhead package
is missing or outside the supported range.

Nuxt 3 is unsupported. Upgrade to Nuxt 4.6 or newer before installing v2.

The DevTools panel now uses the optional `@nuxt/scripts-devtools` package.
Install its matching version as a development dependency, then restart Nuxt.
Core script loading and server proxies work without it.

## Registry configuration

Registry entries now accept a flat object, `'mock'`, or `false`. Nuxt Scripts 2
removes the deprecated `true`, `'proxy-only'`, tuple, nested `scriptOptions`,
and `reverseProxyIntercept` forms.

```diff
scripts: {
   registry: {
-    googleAnalytics: true,
-    plausibleAnalytics: [{ scriptId: 'YOUR_SCRIPT_ID' }, { proxy: false }],
-    calendly: { scriptOptions: { bundle: false } },
-    posthog: { reverseProxyIntercept: false },
+    googleAnalytics: { trigger: 'onNuxtReady' },
+    plausibleAnalytics: { scriptId: 'YOUR_SCRIPT_ID', proxy: false },
+    calendly: { bundle: false },
+    posthog: { proxy: false },
   },
 }
```

Nuxt Scripts 2 also removes the deprecated top-level `globals` array. Use a
keyed object so each script has a stable name.

## Google Maps

Nuxt Scripts 2 removes these v1 compatibility aliases and components:

| Removed                                                        | Replacement                                                    |
| -------------------------------------------------------------- | -------------------------------------------------------------- |
| `center` and `zoom` props on `<ScriptGoogleMaps>`{lang="html"} | `mapOptions.center` and `mapOptions.zoom`                      |
| `googleMaps` template ref key                                  | `mapsApi`                                                      |
| `overlay` template ref key                                     | `overlayView`                                                  |
| `<ScriptGoogleMapsAdvancedMarkerElement>`{lang="html"}         | `<ScriptGoogleMapsMarker>`{lang="html"}                        |
| `<ScriptGoogleMapsPinElement>`{lang="html"}                    | The marker `#content` slot                                     |
| `<ScriptGoogleMapsHeatmapLayer>`{lang="html"}                  | A maintained heatmap library such as [deck.gl](http://deck.gl) |

Google removed `HeatmapLayer` from Maps JavaScript API v3.65, so Nuxt Scripts
no longer ships a component that depends on it.

Nuxt Scripts 2 removes the legacy `googleStaticMapsProxy` option and the
billable Google Maps server proxies. Static maps load directly from Google with
the public browser key. `resolveQueryToLatLng()`{lang="ts"} uses the client Places service.
Apply website and API restrictions to the key, then configure quota limits.

## Registry APIs

Nuxt Scripts 2 removes these deprecated registry API shapes:

| Removed                                    | Replacement                         |
| ------------------------------------------ | ----------------------------------- |
| `proxy.rybbit.pageview()`{lang="ts"}       | `proxy.pageview()`{lang="ts"}       |
| `proxy.ttq('page')`{lang="ts"}             | `proxy.ttq.page()`{lang="ts"}       |
| `proxy.ttq('track', ...)`{lang="ts"}       | `proxy.ttq.track(...)`{lang="ts"}   |
| Matomo `trackPageView` option              | `watch`, which defaults to `true`   |
| Plausible `domain` and `extension` options | `scriptId` and current init options |

## Consumer scopes

Every `useScript()`{lang="ts"} call now returns an Unhead consumer scope.
Component unmount automatically releases callbacks and trigger listeners owned
by that call.

- `dispose()`{lang="ts"} releases only the current consumer.
- `signal` aborts when you dispose that consumer or any caller removes the shared script.
- `script` points to the shared script instance.
- `remove()`{lang="ts"} still removes the shared script for all consumers.

If application code used `remove()`{lang="ts"} as component cleanup, switch it
to `dispose()`{lang="ts"}. In Vue components, manual cleanup is normally no
longer necessary.

## Custom readiness callbacks

The `use` option remains supported. Callback-driven SDKs should migrate
to `resolve({ waitFor })`{lang="ts"}, which automatically removes listeners and
rejects pending readiness when the script lifecycle ends.

```diff
const script = useScript('https://example.com/sdk.js', {
-  use: () => readyPromise.then(() => window.example),
+  resolve: ({ waitFor }) => waitFor((resolve) => {
+    window.onExampleReady = () => resolve(window.example)
+    return () => delete window.onExampleReady
+  }),
 })
```

The bundled Google Maps, YouTube Player, Crisp, and Usercentrics integrations
now use this API. `load()`{lang="ts"} resolves only after each vendor's concrete
SDK API is ready.

## Script triggers

Nuxt's idle-timeout, interaction, and service-worker helpers now return Unhead
trigger functions. Existing `scriptOptions.trigger` usage is unchanged. Custom
trigger functions may return a cleanup callback; Unhead calls it when the
consumer scope is disposed.

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
