Inspired by many blogs that show a nice-looking view counter on every page, I also wanted to develop such a feature for my blog. I’m also using Next.js 14 with the new app router, but instead of storing the page views in a relational database like PostgreSQL, I’ll be using Upstash Redis.
Here is the GitHub repo with the full code.
Example page hosted on Vercel -> https://nextjs14-azureb2c-prisma.vercel.app/
Why Redis and not a Relational DB like PostgreSQL?
Redis offers great commands that make it easy to deduplicate and increment a counter, which is crucial for accuracy.
I want to debounce the counter incrementing to get a more accurate counter. If a user refreshes the page, the counter should only be incremented once. We can do this easily with Redis’ SET command. It has a NX option that will only set the key if it doesn't exist yet and an EX option that will expire the key after a given amount of seconds. By combining both options, we can ensure a single user does not increment the counter multiple times within a given timeframe.
The second command is INCR, incrementing a given key by 1 atomically. And last but not least, we can offload this task from our “default” relational DB.
Next.js Api Route for Redis Operations
We create the file src/app/api/viewcount, where we import our Redis Lib file, which we created in the previous post.
Upstash Redis NPM Package
The same applies to the needed Upstash Redis NPM Package we installed during the previous story.
Vercel EDGE
Upstash and @upstash/redis are compatible with Vercel's edge functions, so first, we will import everything we need, set up Redis, and configure the runtime to be edge.
New Tracking Component “viewcount.tsx”
We pass the slug attribute to the earlier created API route with “UseEffect”.
Project Integration “page.tsx”
As a last step, we must integrate the new Component into our Next.js 14 Project.
Import Redis Lib and viewcount component
Defining const Views on line 222
Using imported component on line 243
Showing views on the bottom (line 282)
Below is the full code (page.tsx)
That’s it. We built and integrated an easy and lightning-fast view counter within minutes. Of course, there is space for a style improvement, etc., but from a functional POV, it works great.

Cloudapp-dev, and before you leave us
Thank you for reading until the end. Before you go: