Back to stories
<Frontend/>

Vue v-for Key Stability: Why Keys Matter and What to Use

Share by

Vue v-for Key Stability: Why Keys Matter and What to Use

In Vue, the key attribute on v-for tells the renderer which item is which across updates. A stable, unique key improves performance and prevents wrong DOM reuse. This post explains why keys matter and when to use an id vs index.


What the key is for

Vue (and Virtual DOM diffing in general) uses the key to match old and new list items. When the list changes (reorder, add, remove), it uses the key to decide:

  • Which existing node to reuse for which new item.
  • Which nodes to add or remove.

If keys are stable (same item → same key over time) and unique (no two items share a key), Vue can patch the list efficiently and keep component state aligned with the right item (e.g. focus, local state).


Prefer a unique id over index

When each item has a stable id (from the server, or a generated id), use it as the key:

<template>
  <div v-for="item in items" :key="item.id">
    {{ item.name }}
  </div>
</template>

Why: Reordering, inserting, or deleting items keeps each key tied to the same logical item. Vue reuses the right DOM nodes and component instances, so you get correct updates and no "state jumping" between items.


Why index as key is risky

Using the array index as key is only safe when the list is static (no reorder, no insert/delete in the middle). If you do:

<div v-for="(item, index) in items" :key="index">
  {{ item.name }}
</div>

and then reorder or splice the list, the index of each item changes. Vue will reuse DOM/components by index: the first node stays "first," the second "second," and so on. So the content updates to the new item, but any internal state (input value, focus, expanded/collapsed) stays attached to the position, not the item. That causes bugs like the wrong row being expanded or the wrong input being focused.


When index is acceptable

Using index as key is acceptable when:

  • The list is purely presentational and has no per-item state.
  • The list is never reordered or filtered in place (e.g. a static table).

As soon as you have reorder, filter, or per-item state, switch to a stable id.


Composite keys

When there is no single id, you can build a composite key from several fields, as long as it is unique and stable for the same item:

<div v-for="item in items" :key="`${item.category}-${item.id}`">
  {{ item.name }}
</div>

Avoid keys that change when the item doesn't (e.g. item.name if the name can be edited).


Summary

  • Key in v-for identifies list items across updates; use it for correct and efficient list patching.
  • Prefer a unique, stable id (e.g. item.id) so reorder/add/remove work correctly and per-item state stays with the right item.
  • Avoid index as key when the list can reorder or when items have local state; use index only for static, stateless lists.
  • Composite keys are fine when they are unique and stable. Stable keys keep Vue's list rendering fast and bug-free.