docs/guide/optimistic-updates.md
Inertia allows you to update the UI immediately without waiting for the server to respond, such as incrementing a like counter, toggling a bookmark, or adding an item to a list. Optimistic updates apply changes instantly while the request is in flight, automatically rolling back if the request fails.
You may chain the optimistic() method before any router visit. The callback receives the current page props and should return a partial update to apply immediately.
import { router } from '@inertiajs/vue3'
router
.optimistic((props) => ({
post: {
...props.post,
likes: props.post.likes + 1,
},
}))
.post(`/posts/${post.id}/like`)
The optimistic update is applied immediately to the current page's props, so your component re-renders with the new values before the request is sent. When the server responds, Inertia replaces the optimistic data with the server's response. If the request fails, the props are automatically reverted to their original values.
The <Form> component supports optimistic updates via the optimistic prop. Since the component manages input data internally, the form data is provided as a second callback argument.
<template>
<Form
action="/todos"
method="post"
:optimistic="
(props, data) => ({
todos: [
...props.todos,
{ id: Date.now(), name: data.name, done: false },
],
})
"
>
<input type="text" name="name" />
<button type="submit">Add Todo</button>
</Form>
</template>
The useForm helper also supports optimistic updates via the same optimistic() method.
<script setup>
import { useForm } from '@inertiajs/vue3'
const props = defineProps({ posts: Array })
const form = useForm({
title: '',
})
function save() {
form
.optimistic((props) => ({
posts: [...props.posts, { title: form.title }],
}))
.post('/posts')
}
</script>
<template>
<input v-model="form.title" />
<button @click="save" :disabled="form.processing">Save</button>
</template>
The useHttp hook supports optimistic updates as well. Since HTTP requests don't interact with Inertia's page props, the optimistic callback receives and updates the form's own data. On failure, the form data is reverted to its pre-request state.
import { useHttp } from '@inertiajs/vue3'
const form = useHttp({
likes: 0,
})
form
.optimistic((data) => ({
likes: data.likes + 1,
}))
.post('/api/likes')
When an optimistic update is applied:
The callback should return a partial object containing only the keys you wish to update. The returned values are shallow-merged with the current data.
Optimistic state is automatically reverted in several scenarios:
Multiple optimistic requests may be in flight at the same time. Inertia tracks which props each optimistic update touched, and server responses will not overwrite a prop until the last optimistic request that modified it has resolved.
You may also pass the optimistic callback directly in the visit options instead of chaining.
import { router } from '@inertiajs/vue3'
router.post(
`/posts/${post.id}/like`,
{},
{
optimistic: (props) => ({
post: { ...props.post, likes: props.post.likes + 1 },
}),
},
)
The inline option works with useHttp submit methods as well.
form.post('/api/likes', {
optimistic: (data) => ({
likes: data.likes + 1,
}),
})