What Is a Side Effect in Vue?

In programming, a side effect is anything a function does to the outside world beyond returning a value: changing the DOM, sending a request to an API, starting a timer, writing to localStorage or updating a global variable. In Vue, side effects are such operations, run when reactive state changes or when a component appears.
Where should side effects run?
- Not in templates or computed: computed functions should only calculate a value. Sending requests or changing other state inside them leads to unexpected loops and bugs.
- watch / watchEffect: for work that should happen when a reactive value changes (for example fetching results from an API when a search box changes).
- Lifecycle hooks: work to do when the component appears goes in onMounted, and clean-up in onUnmounted.
Clean-up
Every side effect you set up should be cleaned up when the component is removed or before the effect runs again; otherwise timers and event listeners pile up and leak memory.
import { createApp, ref, watchEffect } from 'vue';
createApp({
setup() {
const seconds = ref(0);
const running = ref(true);
// Side effect: starts a timer while running is true
watchEffect((onCleanup) => {
if (!running.value) return;
const id = setInterval(() => seconds.value++, 1000);
// Clear the timer before the effect runs again or the component is removed
onCleanup(() => clearInterval(id));
});
return { seconds, running };
},
template: `
<p>Elapsed: {{ seconds }} s</p>
<button @click="running = !running">{{ running ? 'Stop' : 'Resume' }}</button>
`,
}).mount('#app');Here the timer is a side effect. Thanks to onCleanup, pressing "Stop" clears the timer and "Resume" starts it again.
In short, side effects are unavoidable — most of an application's real work is done with them. What matters is running them in the right place (watch, watchEffect, lifecycle hooks) and always cleaning them up.
Have a question about this article? Write to me


