v0 to v1
Use this guide to update a Nuxt Scripts v0 project to v1. The v1 release notes cover the new features.
Most replaced APIs continue to work with deprecation warnings. The table marks the changes that require code updates.
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; slot-passthrough shim remains | 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 uses instance-based initialization (createInstance()), eligibility checks before rendering, and session-based payment flows. See the PayPal docs for the new component API.
- SDK URLs now use v6 endpoints (
/web-sdk/v6/core) PayPalOptionsreduced toclientId,clientToken, andsandbox; provide eitherclientIdorclientToken(v6 configures atcreateInstance()time, not through 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 (#563, #586)
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 no longer share state. Remove any v0 workarounds for multiple players on one page.
Google Tag Manager (#584)
onBeforeGtmStart Callback
v1 calls this hook for cached or preinitialized scripts too. Guard against repeated initialization:
+let initialized = false
useScriptGoogleTagManager({
onBeforeGtmStart: (gtag) => {
+ if (initialized) return
+ initialized = true
// your init code
}
})
Google Maps (implementation commit)
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)
The old component remains as a thin shim and emits a development warning.
-<ScriptGoogleMapsAdvancedMarkerElement :position="{ lat: 0, lng: 0 }" />
+<ScriptGoogleMapsMarker :position="{ lat: 0, lng: 0 }" />
ScriptGoogleMapsPinElement Removed (Compatibility Shim Remains)
The old component now only renders its default slot and emits a development warning; its options prop no longer creates a Google Maps pin. Move the markup into 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)
v1 removes the placeholderOptions, placeholderAttrs, and aboveTheFold props from <ScriptGoogleMaps>. Put the standalone <ScriptGoogleMapsStaticMap> component in the #placeholder slot instead. The slot is empty by default and no longer receives a placeholder URL.
-<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 favor 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)
mapsApi holds the google.maps API namespace. The old googleMaps key remains as a deprecated alias and emits a development warning the first time it is 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 (#589)
v1 reorganizes the generated type templates. Run nuxi prepare after upgrading:
npx nuxi prepare