Mortadha.Dev

Use Vercel KV store in Astro

Let's build together a simple page view counter for every Astro blog page we have, using the new KV store by Vercel.

On May 13, 2023 — 4 min read
AstroVercelKV Store

So I decided to add a page view counter for my blog, one and easy to implement this is to use KV stores. It also coincides with Vercel Ship event which was held between May 1 & May 5, on their first day, they announced their data storage solutions, so I wanted to try their new KV storage solution.

KV Store

A KV store is a simple database that stores data as key-value pairs. You can quickly store and retrieve values using unique keys. It’s like having a box where you put things and label them with keys, so you can easily find and access them later.

For example:

"Name" => "John"
"Age" => 25
"City" => "New York"

We can retrieve values using their respective keys.

Setting up data

Now, let’s decide on the format of the key => value data, so we know that each post has a unique slug, we can use that as an id for the post, so the format would be something like this: post:slug => { "views": value }.

In redis terms, this will translate to a hash, the redis command to set it would be like this:

HSET post:slug views 0

or in our case if we want to increment it, we use the following:

HINCRBY post:slug views 1
  • HSET: create a new hash with the provided fields values
  • HINCRBY: create a new hash if there’s none, or increment hash field value by the provided value
  • post:slug: hash key
  • views: hash field

Building KV store (Vercel)

Now knowing the format of the data, we can start first by creating a new KV store in Vercel dashboard:

Create KV Database - Vercel
Create KV Database - Vercel

Next, we link our database to the project, and then, we copy ENV variables and paste them in our .env file in the root of our project:

.env
KV_REST_API_URL="********"
KV_REST_API_TOKEN="********"

That’s it!

Creating endpoint

In order to change the values in KV store, we need to create an endpoint in Astro, so when we call that endpoint, we make the change to the KV store.

So first, as endpoints are not supported in static output mode, we need to change that to server output mode and use a 3rd party adapter, in our case it’s Vercel, so we need to do the following changes:

astro.config.ts
import vercel from "@astro/vercel/serverless";
 
export default defineConfig({
  output: "server",
  adapter: vercel(),
});

Now we install the Vercel KV SDK package:

pnpm add -D @vercel/kv

Next thing, we need to add this line: export const prerender = true; on the top of each page file that use static generation,

Then, we create a new endpoint file under /src/pages/api/view/, named: [slug].ts with the following content:

[slug].ts
import type { APIRoute } from "astro";
import { createClient } from "@vercel/kv";
 
const { KV_REST_API_URL, KV_REST_API_TOKEN } = import.meta.env;
 
const kv = createClient({
  url: KV_REST_API_URL,
  token: KV_REST_API_TOKEN,
});
 
export const get: APIRoute = async ({ params }) => {
  const { slug } = params;
 
  if (!slug) {
    return new Response(null, { status: 404 });
  }
 
  await kv.hincrby(`post:${slug}`, "views", 1);
 
  return new Response(null, { status: 366 });
};

Now we’ll have a new endpoint: GET /api/view/[slug].

Triggering the endpoint

So now after setting up everything, we need to find a way to trigger and call that endpoint, we can make a simple fetch call to that endpoint, or if we don’t want to use javascript, we can use this little trick: use <img> tag to load the endpoint url instead, it will be something like the following:

<img
  id="hitbox"
  src={`/api/view/${data.slug}`}
  alt="hitbox"
  width="1"
  height="1"
  aria-hidden="true"
/>
<style>
  #hitbox {
    position: absolute;
    left: -9999px;
  }
</style>

And we put that piece of code inside the blog post Astro template, now whenever a blog post renders, it will automatically make a GET request to our endpoint.

Personally, I find this method very elegant, but it may cause some issues with other browsers, it needs to be tested heavily, we don’t want certain browsers not counting views, we cross check views on analytics to see if some browser views are not matching our views counter in our KV store.

Troubleshooting

Currently we may have a problem using endpoints with Vercel SDK on Astro default dev server, instead, we need to use Vercel dev server in order to make use of their KV Store SDK, we just need to run: vercel dev..

We may also have to install the required dependencies if any errors are thrown.


Hope you found this helpful, and as always stay tuned to some more content ✌️

Related