The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →A Vue ref() is not inherently unsafe in Nuxt. The risk is creating a mutable ref once at server module scope and sharing that object across requests. Keep component-owned state inside setup(); use Nuxt’s keyed useState when state must be shared in the Nuxt app and preserved through server rendering and hydration.
Why can Nuxt state leak between users?
With server-side rendering (SSR), a server process can handle many requests while its imported modules remain loaded. A ref created at module scope is created when that module is evaluated, rather than once for each component instance or request. If one request writes user-specific data to that ref, a later request handled by the same process can encounter the same object.
As an Amazon Associate I earn from qualifying purchases.
That is a lifetime and ownership problem, not a flaw in ref(). Nuxt’s v3 state guide warns: “Never define const state = ref() outside of <script setup> or setup() function.” Nuxt’s State Management guide illustrates the distinction between component-scoped refs and state that Nuxt manages for SSR.
The unsafe pattern: a module-level singleton
// Avoid in SSR: created once when this module is evaluated.
export const currentUser = ref<User | null>(null)
This exported object belongs to a long-lived server module, not to one request. If request A stores its user in it and request B later reads it, user-specific state can cross the request boundary. Do not put credentials, personal details, shopping carts, or other per-user mutable data in a server-wide singleton.
#1 Best Overall
A safe local ref: state owned by a component
<script setup lang="ts">
const isOpen = ref(false)
</script>
A ref created in a component’s <script setup> belongs to that component instance. It is suitable for local UI state such as whether a disclosure is open. Nuxt’s warning is about defining shared ref state outside <script setup> or setup(), not about using refs generally.
When should you use useState instead?
Use useState when multiple parts of the Nuxt application need the same SSR-aware state and that state should survive hydration. Nuxt describes it as “a reactive and SSR-friendly shared state.” The Nuxt v4 useState API documentation explains its keyed state and initializer.
Rank #2
// composables/useCart.ts
export const useCart = () => useState<CartItem[]>('cart', () => [])
Give related consumers a stable key: calls using the same key in the same Nuxt application context refer to the shared state associated with it. The initializer supplies its initial value. This is Nuxt-managed state, not a general-purpose process-wide variable; do not substitute a global mutable singleton for request-aware state.
Recommended Free Tools
Choose by scope, sharing, and serialization
| Need | Use | Reason |
|---|---|---|
| State used by one component instance | ref() in setup() or <script setup> |
Its owner and lifetime are the component instance. |
| State shared by components in a Nuxt app and retained through hydration | useState with a stable key |
Nuxt manages keyed shared state for SSR and client hydration. |
| Mutable user-specific state held in an imported server module | Neither as a process-wide singleton; move it to an appropriate request-aware design | A long-lived module object can be reused across requests. |
What belongs in useState?
Nuxt serializes useState data as JSON in its payload so the client can restore state during hydration. Store JSON-serializable data, such as plain objects, arrays, strings, numbers, booleans, or null. Nuxt cautions against classes, functions, and symbols unless custom serialization is configured; see the API’s serialization guidance.
For authentication or tenant-specific state, check the boundaries of the application’s request context and data-fetching design rather than assuming that a globally mutable variable is isolated per user. A stable key identifies state within the Nuxt application context; it is not a substitute for deciding which data belongs to which request or user.
How does hydration affect the choice?
Nuxt first renders HTML on the server, then the browser hydrates the app by recreating the client-side application, matching it to the server output, and attaching event listeners. Nuxt’s v3 lifecycle guide describes the server and client lifecycle; its v4 lifecycle guide explains hydration and recommends SSR-friendly data composables.
Rank #4
Keep the initial server and client data consistent. If each side independently generates a different initial value, the client may not match the server-rendered output. For server-fetched data that should be reused during hydration, use Nuxt’s SSR-friendly data-fetching composables rather than inventing a separate module-level cache.
Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Repair Windows errors before they cause bigger problems3Fix the driver behind crashes, sound loss and screen glitchesWhich Nuxt version applies?
The cited v3 state guide identifies Nuxt 3.21.11 and states that Nuxt 3 reached end of life on July 31, 2026, with no further bug fixes or security patches; it directs users to Nuxt 4 or extended support. Check the Nuxt major version and support arrangement for your project before applying version-specific guidance. The core distinction here—component-owned state versus mutable state kept in a long-lived server module—is about scope and lifetime, not a particular minor-version signature.
Quick Recap
Best Value
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




