Release·  

Nuxt 3.17

Nuxt 3.17 is out - bringing a major reworking of the async data layer, a new built-in component, better warnings, and performance improvements!
Daniel Roe

Daniel Roe

@danielroe.dev

📊 Data Fetching Improvements

A major reorganization of Nuxt's data fetching layer brings significant improvements to useAsyncData and useFetch.

Although we have aimed to maintain backward compatibility and put breaking changes behind the experimental.granularCachedData flag (disabled by default), we recommend testing your application thoroughly after upgrading. You can also disable experimental.purgeCachedData to revert to the previous behavior if you are relying on cached data being available indefinitely after components using useAsyncData are unmounted.

Read the original PR for full details.

Consistent Data Across Components

All calls to useAsyncData or useFetch with the same key now share the underlying refs, ensuring consistency across your application:

<!-- ComponentA.vue -->
<script setup>
const { data: users, pending } = useAsyncData('users', fetchUsers)
</script>

<!-- ComponentB.vue -->
<script setup>
// This will reference the same data state as ComponentA
const { data: users, status } = useAsyncData('users', fetchUsers)
// When either component refreshes the data, both will update consistently
</script>

This solves various issues where components could have inconsistent data states.

Reactive Keys

You can now use computed refs, plain refs, or getter functions as keys:

const userId = ref('123')
const { data: user } = useAsyncData(
  computed(() => `user-${userId.value}`),
  () => fetchUser(userId.value)
)

// Changing the userId will automatically trigger a new data fetch
// and clean up the old data if no other components are using it
userId.value = '456'

Optimized Data Refetching

Multiple components watching the same data source will now trigger only a single data fetch when dependencies change:

// In multiple components:
const { data } = useAsyncData(
  'users', 
  () => $fetch(`/api/users?page=${route.query.page}`),
  { watch: [() => route.query.page] }
)

// When route.query.page changes, only one fetch operation will occur
// All components using this key will update simultaneously

🎭 Built-In Nuxt Components

<NuxtTime> - A new component for safe time display

We've added a new <NuxtTime> component for SSR-safe time display, which resolves hydration mismatches when working with dates (#31876):

<NuxtTime :time="new Date()" format="YYYY-MM-DD" />

The component accepts multiple time formats and gracefully handles both client and server rendering.

Enhanced <NuxtErrorBoundary>

The <NuxtErrorBoundary> component has been converted to a Single File Component and now exposes error and clearError from the component - as well as in the error slot types, giving you greater ability to handle errors in your templates and via useTemplateRef (#31847):

<NuxtErrorBoundary @error="handleError">
  <template #error="{ error, clearError }">
    <div>
      <p>{{ error.message }}</p>
      <button @click="clearError">Try again</button>
    </div>
  </template>
  
  <!-- Content that might error -->
  <MyComponent />
</NuxtErrorBoundary>

🔗 Router Improvements

<NuxtLink> now accepts a trailingSlash prop, giving you more control over URL formatting (#31820):

<NuxtLink to="/about" trailing-slash>About</NuxtLink>
<!-- Will render <a href="/about/"> -->

🔄 Loading Indicator Customization

You can now customize the loading indicator with new props directly on the component (#31532):

  • hideDelay: Controls how long to wait before hiding the loading bar
  • resetDelay: Controls how long to wait before resetting loading indicator state
<template>
  <NuxtLoadingIndicator :hide-delay="500" :reset-delay="300" />
</template>

📚 Documentation as a Package

The Nuxt documentation is now available as an npm package! You can install @nuxt/docs to access the raw markdown and YAML content used to build the documentation website (#31353).

💻 Developer Experience Improvements

We've added several warnings to help catch common mistakes:

  • Warning when server components don't have a root element #31365
  • Warning when using the reserved runtimeConfig.app namespace #31774
  • Warning when core auto-import presets are overridden #29971
  • Error when definePageMeta is used more than once in a file #31634

🔌 Enhanced Module Development

Module authors will be happy to know:

  • A new experimental.enforceModuleCompatibility allows Nuxt to throw an error when a module is loaded that isn't compatible with it (#31657). It will be enabled by default in Nuxt v4.
  • You can now automatically register every component exported via named exports from a file with addComponentExports #27155

🔥 Performance Improvements

Several performance improvements have been made:

  • Switched to tinyglobby for faster file globbing #31668
  • Excluded .data directory from type-checking for faster builds #31738
  • Improved tree-shaking by hoisting the purgeCachedData check #31785

✅ Upgrading

Our recommendation for upgrading is to run:

npx nuxi@latest upgrade --dedupe

This refreshes your lockfile and pulls in all the latest dependencies that Nuxt relies on, especially from the unjs ecosystem.

Full release notes

Read the full release notes of Nuxt v3.17.0.

A huge thank you to everyone who's been a part of this release. ❤️