October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

Vue Composables: Why State Is Shared—and How to Choose the Right Scope

Vue composable state is shared or local according to where it is created. See the patterns for per-call state, app-wide stores, provide/inject, Pinia, and SSR.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If separate components see the same composable state, check where its reactive object is created. A ref() or reactive() value declared at module scope is one shared object; one created inside the composable function is ordinarily new for each call. The useX name does not determine its lifetime.

Why is my composable state shared between components?

A Vue composable is a function pattern for encapsulating and reusing stateful logic. It is not a special kind of Vue object with automatic global or component-local lifetime. Vue’s glossary describes composables as functions that typically return a plain object containing refs and functions: Vue glossary: Composable.

As an Amazon Associate I earn from qualifying purchases.

The key is where the state is initialized. Consider this module:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import { ref } from 'vue'

const count = ref(0)

export function useCounter() {
  return { count }
}

The module creates count once. Each call to useCounter() returns a reference to that same ref, so a change made through one consumer is visible to the others.

Move the initialization into the function to make each invocation create its own state:

import { ref } from 'vue'

export function useCounter() {
  const count = ref(0)
  return { count }
}

Now each call ordinarily gets a separate counter. Vue’s state-management guide demonstrates both local state created by a composable call and global state returned from a composable: Vue: State Management.

Cheat sheet: choose the state lifetime

What needs to share state? Pattern Ownership and trade-off
One component or composable invocation Create refs or reactive state inside the composable function. Each invocation gets its own instance; the caller owns that instance’s use.
Several components in one client app, intentionally Use module-scope reactive state or a store. All consumers share one source of truth. Make shared mutations explicit and centralized.
Descendants of a particular component Use provide and inject. The provider owns a subtree-scoped dependency; a closer provider overrides an ancestor.
A simple app-wide store Use a small reactive object or ref as a store. Can be sufficient for simple needs; define where mutations belong.
A larger production app with stronger conventions and tooling needs Consider Pinia. Vue recommends Pinia for new applications and documents its tooling and SSR support.
State shared among components during one SSR request Create a fresh app and store for each request, then provide that store. Consumers within the request share the instance; separate requests must not.

How do I make composable state local to each component?

  1. Put initialization inside the composable. Create the ref() or reactive() value in the function body, rather than at the top level of the module.
  2. Return the invocation’s state. Return the ref or reactive object and any functions that operate on it. Components calling the composable separately then receive separate instances.
  3. Check for an intentional connection elsewhere. If the composable injects a provided store, imports a module-level store, or otherwise returns a shared object, that design can still make consumers share state.

Use this pattern for state whose lifecycle belongs to an individual component, such as a local form draft or a component-specific counter. If the state must be shared, choose and document the intended boundary instead of relying on where consumers happen to import the composable.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When should state be shared?

Across one client application

Module-scope reactive state can be a straightforward shared source of truth in a browser-only app. Vue explicitly notes that a composable can return global state, and that shared reactive state can also use APIs such as ref() or computed(). See Vue’s state-management guidance. Keep mutations understandable: for example, expose an action such as increment() rather than letting unrelated consumers change shared state without a clear ownership rule.

Within a component subtree

provide/inject suits dependencies or state needed by descendants of a particular component, without passing the value through every intermediate component’s props. The nearest matching provider supplies the value. Vue explains the API and reactive values in its Provide / Inject guide and dependency-injection API reference.

A provider can keep ownership of updates by providing functions that perform them. It can also provide a readonly() view when consumers should observe state but not mutate it directly. If consumers need to request changes, provide an update function rather than handing out unrestricted mutation access. For larger codebases, use Symbol injection keys to reduce naming collisions.

For a larger app

A hand-rolled reactive store may be enough for a simple case. Vue’s state-management guide identifies team conventions, Vue DevTools integration, hot module replacement, and SSR support as concerns addressed by Pinia, which it describes as maintained by the Vue core team and recommends for new applications. The same guide says Vuex still works but is in maintenance mode and is not receiving new features. These are Vue’s current documentation recommendations, not a requirement to use Pinia for every shared value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What changes when the app uses SSR?

A module-scope singleton in a server process can outlive an individual request. If request-specific data is stored in that singleton, another request handled by the same process may observe it. That can cause cross-request state pollution and may expose one user’s state to another.

For SSR, create a new app and store for each request, then make that request’s store available at app level through provide/inject. Vue’s SSR guide describes this approach: Vue: Server-Side Rendering. Pinia is also designed with SSR in mind, but the essential safeguard is that request-specific state belongs to a request-specific app/store instance.

This is not a reason to avoid every module-level singleton. In a client-only app, a singleton can be intentional. The concern is its lifetime relative to server requests: a server process may serve multiple users while retaining module state.

TypeScript and safer injection

In TypeScript, Vue’s InjectionKey<T> lets the provider and injector share a type for the injected value. Vue documents this pattern in its Composition API TypeScript guide. An injection can still be undefined when no provider exists, so supply a fallback where appropriate or check for absence before using it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.