Imagine using code to predict the future. Imagine serving instantaneous UI feedback when a user interacts with the server.

This is now possible when combining Optimistic Updates with Server Actions in Next.js 14.

We will create a simple application which prompts the user to enter a message, send this message to a database, and display every sent message in a list which updates instantly (with zero server delay).

So without further ado… Lets dive right in.

Table of Contents

Setup Next.js 14 Project EnvironmentuseOptimisticCreating the Optimistic ComponentCreating the send Server Action

Setup Next.js 14 Project Environment

To setup a Next.js project, please check out the instructions here. The installation process generally consists of running the following command in the terminal.

npx create-next-app@latest


useOptimistic is a new special hook that has been introduced in React Canary; it is no longer experimental and compatible with Next.js 14.

useOptimistic ‘optimistically’ updates the UI, which means it can “predict” what needs to be rendered as a result of an asynchronous function call.

Here is the body of the useOptimistic hook:

const [optimisticState, addOptimistic] = useOptimistic(
// updateFn
(currentState, optimisticValue) => {
// merge and return new state
// with optimistic value

You pass in an immutable state object alongside a callback (that follows the reducer pattern) with a mutable version of the currentState that can be merged with an optimisticValue to update the existing state.

Creating the “Optimistic” Component

Now that we understand what the useOptimistic hook does, it is time to create a working example showcasing it’s power.

Create a file called src/components/Optimistic.tsx and copy this code:

“use client”

import { useOptimistic, useRef } from “react”
import { Message } from “@/types”

import { send } from “@/app/_actions”

export function Optimistic({ messages }: { messages: Message[] }) {
const formRef = useRef<HTMLFormElement>(null)
const [optimisticMessages, addOptimisticMessage] = useOptimistic(
(state: Message[], { message }: Message) => [
{ message, sending: true },
] )

return (
{optimisticMessages.map(({ message, sending }, k) => (
<div key={k}>
{!!sending && <small> (Sending…)</small>}
action={async (formData: FormData) => {
const message = formData.get(“message”) as string

addOptimisticMessage({ message, sending: true })

await send(message)
<input type=”text” name=”message” />
<button type=”submit”>Send Message</button>
}Here useOptimistic takes messages of type Message defined as follows:export type Message = {
message: string
sending: boolean | null
}The messages state updates optimistically regardless of the progress of the message being sent to the server, leading to a snappy UI experience.Other details that I have included are extra such as:{!!sending && <small> (Sending…)</small>}

This is only for demonstrational purposes to highlight the message being updated in the list instantly while the message is being sent into a database.

Creating the “send” Server Action

To retain list data, we need to actually store the message to a database, here is how you would achieve this:

Create a file called src/app/_actions/index.ts with this code:

“use server”

import { setTimeout } from “timers/promises”
import { revalidatePath } from “next/cache”

import { serverClient } from “../_trpc/serverClient”

export async function send(message: string) {
await serverClient.messageRouter.sendMessage(message)
await setTimeout(1000)

return message
}This code mocks a one second delay and also sends the message into a PlanetScale database. I wrote an article about my ideal Next.js 14 project tempalte including PlanetScale, Drizzle ORM, Auth.js and many other technologies; here is a free template below:

The Complete Next.js 14 Starter Kit


Here is a snapshot when I send a message string “x”:

Message being optimistically updated in the UI.

And one second later:

Message actually sent to database.

So the message “x” instantly appears on the screen due to optimistic updates, and this masks the appearance of a database delay which is revolutionary for UX!

If you enjoyed this article, check out my profile for many more stories like this, and stay tuned for future articles! 👍

Similar Articles 📰

Authentication in two lines of code: Auth.js + Next.js 14Authentication in two lines of code (PART 2): PlanetScale + Drizzle IntegrationThe King of UI: Enter Mantine + Next.js 14

Connect With Me 🌐

DanielCraciunGitHubDaniel Craciun | LinkedIn

Affiliate Links 🏷️🔗

Notion: Use this to manage your programming projects.Notion AI: The AI Tool that gave me 15,000 monthly readers on medium.

Optimistic Updates in Next.js 14 was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.

​ Level Up Coding – Medium

about Infinite Loop Digital

We support businesses by identifying requirements and helping clients integrate AI seamlessly into their operations.

Gartner Digital Workplace Summit Generative Al

GenAI sessions:

  • 4 Use Cases for Generative AI and ChatGPT in the Digital Workplace
  • How the Power of Generative AI Will Transform Knowledge Management
  • The Perils and Promises of Microsoft 365 Copilot
  • How to Be the Generative AI Champion Your CIO and Organization Need
  • How to Shift Organizational Culture Today to Embrace Generative AI Tomorrow
  • Mitigate the Risks of Generative AI by Enhancing Your Information Governance
  • Cultivate Essential Skills for Collaborating With Artificial Intelligence
  • Ask the Expert: Microsoft 365 Copilot
  • Generative AI Across Digital Workplace Markets
10 – 11 June 2024

London, U.K.