Share state across components without leaking it between users — the server pitfall to avoid, and useState the right way.
Why: the server renders pages for many users at once. A ref() created at the top level of a module is SHARED across all of them, so one user could see another’s data. Never put shared state in a plain module-level ref.
// DON'T: this ref is created once and shared by every visitor on the server
import { ref } from 'vue'
export const user = ref(null) // ⚠️ leaks data between usersWhy: useState is Nuxt’s SSR-safe shared state. It keeps a separate value per request on the server, and carries it to the browser so the client doesn’t reset it. The first argument is a unique key.
<script setup lang="ts">
// Same key anywhere = same state, safely per request
const count = useState('count', () => 0)
</script>
<template>
<button @click="count++">Count: {{ count }}</button>
</template>Why: instead of repeating the key everywhere, wrap useState in a composable. Now every component calls useCounter() and shares the same state — typo-proof and reusable. Note: files in app/composables are auto-imported.
// app/composables/useCounter.ts
export function useCounter() {
return useState('counter', () => 0)
}<!-- any component — no import needed -->
<script setup lang="ts">
const counter = useCounter()
</script>
<template>
<button @click="counter++">Count: {{ counter }}</button>
</template>