Building Real-Time Notifications with Upstash Redis, Next.js Server Actions and Vercel
In this post, I talk about how I built real time notifications using Server-Sent Events with Upstash Redis, Next.js Server Actions and Vercel. Leveraging message channels in Upstash Redis can significantly enhance the communication architecture of your applications, making them more responsive and dynamic.
Demo
What we’ll be using
- Next.js (Front-end and Back-end)
- Upstash Redis (Server-Sent Events with PUBLISH command)
- Tailwind CSS (Styling)
- Vercel (Deployment)
What you'll need
- Node.js 18
- An Upstash account
- A Vercel account
Setting up Upstash Redis
Once you have created an Upstash account and are logged in you are going to go to the Redis tab and create a database.
After you have created your database, you are then going to the Details tab. Scroll down until you find the Connect your database section. Copy the Redis URL and save it somewhere safe, we’ll be using it as UPSTASH_REDIS_URL
as our environment variable.
Also, scroll down until you find the REST API section and select the .env
button. Copy the content and save it somewhere safe, we’ll be using the variables obtained as UPSTASH_REDIS_REST_URL
and UPSTASH_REDIS_REST_TOKEN
.
Setting up the project
To set up, just clone the app repo and follow this tutorial to learn everything that's in it. To fork the project, run:
Once you have cloned the repo, you are going to create a .env file. You are going to add the items we saved from the above sections.
It should look something like this:
Note how at the UPSTASH_REDIS_URL
variable says "rediss" and not "redis", that's to use the TLS/SSL option.
After these steps, you should be able to start the local environment using the following command:
Repository Structure
This is the main folder structure of the project. I have marked in red the files that will be discussed further in this post that deals with the following:
- Understanding Message Channels in Upstash Redis
- Creating Server-Sent Events API in Next.js App Router
- Setup Next.js Server Actions with Upstash Redis to publish notifications
- Setup Next.js frontend to persistently listen and display notifications in real-time
Understanding Message Channels in Upstash Redis
In Upstash Redis, the publish/subscribe model is at the core of message channels. Publishers broadcast messages to named channels, and subscribers are able to receive messages from specific channels in real-time. This model enables seamless communication between different parts of an application.
Here’s how messages can be published to a channel using the Edge compatible library, @upstash/redis
👇🏻
Here’s how subscribers can listen to a Upstash Redis channel (here, posts
) with Node compatible library, ioredis
👇🏻
Upon publishing a message to a channel, all subscribers instantly receive the message, allowing for efficient and real-time communication within Upstash Redis.
Creating Server-Sent Events API in Next.js App Router
Server-Sent Events are a powerful way to send new data in real time without the need for multiple client requests. Unlike traditional request-response mechanisms, SSE enables a unidirectional flow of data from the server to the client over a single, long-lived HTTP connection.
Here’s how you can implement Server-Sent Events in Next.js App Router 👇🏻
Publishing Messages to Upstash Redis using Next.js Server Actions
Next.js Server Actions allow you to define server-side logic directly within your frontend code in Next.js. This saves the process of creating API Routes manually and the hassle of submitting and tracking form submission status(es).
With use server
at the top of the function, we’re able to make sure that the functions runs only server-side. Inside our form submission Server Action, we extract the message
value from the form, use Vercel Header to obtain the country of the user and publish the information as a message to the posts
Upstash Redis message channel.
To invoke this Server Action as the form is submitted, we pass it as the handler to the form action
event.
Setup Next.js frontend to display pending state during Form Submission with React’s useFormStatus hook
The following code demonstrates the setup of a Next.js Form client side component to handle form submission and display a pending
state using React's useFormStatus
hook. Let's break down the key elements of the code:
- Importing the recently released
[useFormStatus
hook from React](https://react.dev/reference/react-dom/hooks/useFormStatus), that gives you status information of the last form submission. - Using the
pending
state reactive variable indicating whether the form submission is in progress. - If the submission is not pending,
reset
the form. - Use the
pending
boolean to show conditional states of the form.
Setup Next.js frontend to persistently listen to Server-Sent Events
In this section, we’ll learn how to setup a minimal listener to Server-Sent Events API messages, and an approach to persist the connection to the SSE API.
Listening to Server-Sent Events API in React Frontend
To listen to SSE API in our client side component in React, we make use of the useEffect
hook. To establish a connection to the SSE API, create a new EventSource
instance pointing to the /api/stream
endpoint. Then attach an event listener for the message
event, where incoming data from the stream is parsed as JSON and further processed or displayed in the component.
Finally, the code includes a cleanup function to close the SSE connection when the component is unmounted, preventing potential memory leaks.
Persisting Connection to Server-Sent Events API in React Frontend
In the enhanced version of the React component, we've implemented a mechanism to ensure a continuous and persistent connection to the SSE API by handling errors and automatically reconnecting.
This is achieved through the connectToStream
function which is responsible for establishing and maintaining a connection to the SSE API.
Here's a breakdown of its functionalities 👇🏻
- Initial Connection and Message Handling:
The function creates a new EventSource
instance, connecting to the /api/stream
endpoint.
Further, it sets up an event listener for the message
event, where incoming data from the stream is parsed as JSON. The parsed data can then be processed or displayed in the React component.
- Error Handling and Automatic Reconnection:
An additional event listener is set for the error
event. In case of any error, such as a connection failure, the event source is closed.
After closing, the function utilizes setTimeout
to trigger a reconnection after a minimal delay of 1 millisecond. This small delay helps in creating a smoother and continuous reconnection process without overwhelming the server with rapid connection attempts
- Handling SSE API Source Closure:
The onclose
event is utilised to detect when the SSE API source is closed. Upon closure, the function schedules another attempt to connect to the stream after a brief delay.
By combining these strategies, the function ensures that the connection to the SSE API remains persistent. Even in the face of errors or closures, the React component will keep attempting to reconnect with minimal delay, effectively maintaining a continuous connection.
Deploy to Vercel
The repository is ready to deploy to Vercel. Follow the steps below to deploy seamlessly with Vercel 👇🏻
- Create a
GitHub Repository
with the app code - Create a
New Project
in Vercel Dashboard - Link the created
GitHub Repository
as your new project - Scroll down and update the
Environment Variables
from the.env
locally - Deploy! 🚀
References
GitHub Repo | https://github.com/rishi-raj-jain/upstash-nextjs-publish-messages-with-sse-example |
---|---|
Server Sent Events | https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events |
Next.js Server Actions | https://nextjs.org/docs/app/api-reference/functions/server-actions |
Next.js Streaming | https://vercel.com/docs/functions/streaming/quickstart |