v0 to v1
This guide covers the breaking changes and deprecations in Nuxt Scripts v1. For an overview of what's new, see the v1 Release Notes.
Summary
| Change | Status | What to do |
|---|---|---|
Registry entry auto-loads without trigger | Build warning | Add trigger: 'onNuxtReady' or trigger: false |
[input, options] tuple form | Still works | Optional: switch to flat config |
true shorthand | Deprecated | Use { trigger: 'onNuxtReady' } |
| PayPal SDK v5 API | Removed | Migrate to v6 (see below) |
ScriptYouTubePlayer width/height | Still work | Optional: use ratio prop |
ScriptYouTubePlayer placeholder object-fit: contain default | Changed to cover | Set placeholder-object-fit="contain" to restore |
GTM onBeforeGtmStart timing | Now fires for cached scripts | Guard with if (initialized) return |
ScriptGoogleMaps markers/centerMarker props | Removed | Use child <ScriptGoogleMapsMarker> |
ScriptGoogleMaps placeholderOptions/placeholderAttrs/aboveTheFold props | Removed | Use <ScriptGoogleMapsStaticMap> in #placeholder |
ScriptGoogleMaps :center/:zoom props | Deprecated | Use :map-options="{ center, zoom }" |
ScriptGoogleMaps googleMaps ref key | Deprecated | Use mapsApi |
ScriptGoogleMapsAdvancedMarkerElement | Deprecated | Use ScriptGoogleMapsMarker |
ScriptGoogleMapsPinElement | Removed | Use #content slot on ScriptGoogleMapsMarker |
| Type templates | Reorganized | Run nuxi prepare |
Registry Config
Scripts No Longer Auto-Load Without a trigger
In v0, any configured registry entry auto-loaded globally via defaultScriptOptions.trigger: 'onNuxtReady'. In v1, presence registers infrastructure (types, bundling, proxy routes) but does not inject a <script> tag unless trigger is set. A build warning fires when you supply config values without a trigger. See PR #661.
scripts: {
registry: {
- googleAnalytics: { id: 'G-XXXXXX' },
+ googleAnalytics: { id: 'G-XXXXXX', trigger: 'onNuxtReady' },
}
}
If you load the script on demand from a composable (useScriptGoogleAnalytics(), etc.) rather than globally, set trigger: false explicitly. This silences the build warning and keeps proxy routes, types, and bundling wired up without injecting a <script> tag.
export default defineNuxtConfig({
scripts: {
registry: {
googleAnalytics: { id: 'G-XXXXXX', trigger: false }, // composable-driven
}
}
})
Legacy Shorthand (still works)
The [input, options] tuple form, true shorthand, and 'mock' string form all continue to work. true emits a deprecation warning.
scripts: {
registry: {
- googleAnalytics: true,
+ googleAnalytics: { trigger: 'onNuxtReady' },
- plausibleAnalytics: [{ domain: 'mysite.com' }, { trigger: 'onNuxtReady' }],
+ plausibleAnalytics: { domain: 'mysite.com', trigger: 'onNuxtReady' },
cloudflareWebAnalytics: 'mock', // unchanged
}
}
Breaking Changes
PayPal SDK v6 (#628)
PayPal v6 moves to instance-based initialization (createInstance()), eligibility-first rendering, and session-based payment flows. The component API has changed significantly. See the PayPal docs.
- SDK URLs now use v6 endpoints (
/web-sdk/v6/core) PayPalOptionsreduced toclientId?,clientToken?,sandbox?(v6 configures atcreateInstance()time, not via URL query params)- Sandbox mode defaults to
truein development ScriptPayPalMarksremoved; no v6 equivalent, usesdkInstance.findEligibleMethods()insteadPayPalNamespacetype replaced withPayPalV6Namespace
<ScriptPayPalButtons> no longer renders buttons directly. It now exposes the v6 SDK instance via a #default scoped slot:
-<ScriptPayPalButtons
- :client-id="clientId"
- @paypal-payment-success="onSuccess"
-/>
+<ScriptPayPalButtons :client-id="clientId" :components="['paypal-payments']">
+ <template #default="{ sdkInstance }">
+ <button @click="pay(sdkInstance)">Pay with PayPal</button>
+ </template>
+</ScriptPayPalButtons>
Payment flow uses sessions instead of button callbacks:
const eligibility = await sdkInstance.findEligibleMethods()
if (eligibility.isEligible('paypal')) {
const session = sdkInstance.createPayPalOneTimePaymentSession({
onApprove: async (data) => { /* capture order */ },
})
await session.start({ presentationMode: 'auto' }, createOrderPromise)
}
-import type { PayPalNamespace } from '@paypal/paypal-js'
+import type { PayPalV6Namespace, SdkInstance } from '@paypal/paypal-js/sdk-v6'
YouTube Player
Aspect Ratio
Use ratio prop instead of deriving aspect ratio from width/height. The width and height props still work for iframe dimensions, but no longer drive the wrapper's aspect ratio.
<ScriptYouTubePlayer
video-id="..."
- :width="1280"
- :height="720"
+ ratio="16/9"
/>
Default is 16/9.
Placeholder Image
Default object-fit changed from contain to cover. To restore v0 behavior:
<ScriptYouTubePlayer video-id="..." placeholder-object-fit="contain" />
Multiple Players
Player instances are now properly isolated. Remove any workarounds you had for running multiple players on the same page.
Google Tag Manager
onBeforeGtmStart Callback
Now fires for cached/pre-initialized scripts. Guard against multiple calls:
+let initialized = false
useScriptGoogleTagManager({
onBeforeGtmStart: (gtag) => {
+ if (initialized) return
+ initialized = true
// your init code
}
})
Google Maps
v1 consolidates the Google Maps marker components, removes the legacy google.maps.Marker API, and extracts the static placeholder into a standalone component.
ScriptGoogleMapsAdvancedMarkerElement → ScriptGoogleMapsMarker (deprecated)
Still works via a thin shim, emits a dev deprecation warning.
-<ScriptGoogleMapsAdvancedMarkerElement :position="{ lat: 0, lng: 0 }" />
+<ScriptGoogleMapsMarker :position="{ lat: 0, lng: 0 }" />
ScriptGoogleMapsPinElement Removed
Use the #content slot on <ScriptGoogleMapsMarker>:
-<ScriptGoogleMapsAdvancedMarkerElement :position="pos">
- <ScriptGoogleMapsPinElement :options="{ background: 'red' }" />
-</ScriptGoogleMapsAdvancedMarkerElement>
+<ScriptGoogleMapsMarker :position="pos">
+ <template #content>
+ <div class="custom-pin" style="background: red;">📍</div>
+ </template>
+</ScriptGoogleMapsMarker>
markers and centerMarker Props Removed
Use child <ScriptGoogleMapsMarker> components instead:
-<ScriptGoogleMaps
- :center="center"
- :markers="[{ position: { lat: 0, lng: 0 } }]"
- center-marker
-/>
+<ScriptGoogleMaps :map-options="{ center, zoom: 12 }">
+ <ScriptGoogleMapsMarker :position="center" />
+ <ScriptGoogleMapsMarker :position="{ lat: 0, lng: 0 }" />
+</ScriptGoogleMaps>
Static Placeholder Props Removed (#673)
placeholderOptions, placeholderAttrs, and aboveTheFold props removed from <ScriptGoogleMaps>. Compose with the new standalone <ScriptGoogleMapsStaticMap> component inside the #placeholder slot instead. The slot no longer receives a placeholder URL string and is empty by default.
-<ScriptGoogleMaps
- :center="center"
- :zoom="7"
- above-the-fold
- :placeholder-options="{ maptype: 'satellite' }"
- :placeholder-attrs="{ class: 'rounded' }"
-/>
+<ScriptGoogleMaps :map-options="{ center, zoom: 7 }">
+ <template #placeholder>
+ <ScriptGoogleMapsStaticMap
+ :center="center"
+ :zoom="7"
+ loading="eager"
+ maptype="satellite"
+ :img-attrs="{ class: 'rounded' }"
+ />
+ </template>
+</ScriptGoogleMaps>
Top-Level :center / :zoom Deprecated (#694)
Deprecated in favour of passing them via :map-options. Both APIs still work; the legacy form emits a dev-mode warning. When both are set, mapOptions wins.
-<ScriptGoogleMaps :center="{ lat, lng }" :zoom="12" />
+<ScriptGoogleMaps :map-options="{ center: { lat, lng }, zoom: 12 }" />
Template Ref googleMaps → mapsApi (#695)
Renamed to better reflect what it holds (the google.maps API namespace, not the component itself). The old key still works as a deprecated alias and emits a one-shot dev-mode warning when read.
const mapRef = ref()
onMounted(() => {
- console.log(mapRef.value?.googleMaps)
+ console.log(mapRef.value?.mapsApi)
})
The same rename applies to <ScriptGoogleMapsOverlayView>: its exposed overlay key is now overlayView, with overlay kept as a deprecated alias.
const overlayRef = ref()
onMounted(() => {
- console.log(overlayRef.value?.overlay)
+ console.log(overlayRef.value?.overlayView)
})
Type Augmentation
Templates reorganized. Run nuxi prepare after upgrading:
npx nuxi prepare