Skip to content

Composables vs utility functions ​

Use composables only when you need Vue's reactivity system or lifecycle hooks. Pure functions that don't require reactive state should be regular utility functions.

Composables are for:

  • Reactive state that persists across component lifecycle
  • Lifecycle-aware logic (onMounted, onUnmounted, etc.)
  • Watchers and computed properties

Utility functions are for:

  • Pure transformations (formatting, calculations)
  • Stateless operations
  • Functions that work outside Vue context

Composables should not:

  • Directly manipulate DOM elements
  • Handle CSS/styling logic
  • Contain template-specific code
  • Trigger UI side effects (toasts, modals, alerts)

Instead of showing notifications or dialogs inside a composable, expose error and status state and let the component decide how to present it.

Example:

typescript
// Composable - needs reactivity and lifecycle
function useWindowSize() {
  const width = ref(window.innerWidth)
  onMounted(() => window.addEventListener("resize", update))
  onUnmounted(() => window.removeEventListener("resize", update))
  return { width }
}

// Utility - pure function, no reactivity needed
function formatDate(date: Date): string {
  return date.toLocaleDateString()
}

Rule for AI agents ​

PREFER plain utility functions over composables unless you need reactivity or lifecycle hooks. Expose state, let components handle presentation.

Eslint rule ​

No ESLint rule available

Source ​