I built an URL shortener with Cloudflare KV
Tags: urlshortener, bitly, shortlink, cloudflare
Published: 2023-12-09 10:49:55

---
title: I built an URL shortener with Cloudflare KV
published: true
description: How to build your own URL shortener with Cloudflare KV
tags: urlshortener, bitly, shortlink, cloudflare
#cover_image:https://github.com/dayschedule/idm/raw/main/assets/url-shortener.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-12-09 10:47 +0000
---

I am building an open source, highly scalable, and low-cost [URL shortener with Cloudflare KV](https://github.com/dayschedule/idm)

![URL shortening software](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h311hzymq49wsdho18bt.png)

By low-cost I mean, just $5 per month on Cloudflare worker and a free plan for basic requirement -

## Idea

At [DaySchedule](https://dayschedule.com/), we had many customer upvoted for a URL shortener feature with auto-expirable links to book an appointment instead sharing their original URL.

So, I decided to try Cloudflare for this project - 

By leveraging Cloudflare KV's capabilities, the goal was to develop a solution that offered not only [URL shortening](https://idm.in/) but also customization options, analytics, and scalability, all while maintaining a significantly lower cost compared to our established services on AWS.

## Features

- [Expirable links](https://developers.cloudflare.com/kv/api/write-key-value-pairs/#expiring-keys) using `cacheTtl` option on KV
- Custom domain using Cloudflare for SaaS
- Analytics using [Worker analytics](https://developers.cloudflare.com/analytics/analytics-engine/worker-querying/#querying)

## API

I used [hono.dev](https://hono.dev/) by @yusukebe for API routing, and it's blazing fast and offers Cloudflare pages template to build Edge projects quickly.

Here is an example of `server.ts` from their docs -

```
import { Hono } from 'hono'
const app = new Hono()

app.get('/', (c) => c.text('Hono!'))

export default app
```

## Controller

The [`/links` API](https://github.com/dayschedule/idm/blob/main/functions/routes/links.ts) is all I need to create, update and manage the short links.

```
const links = new Hono<{ Bindings: Bindings }>();

links.post(
  '/',
  validator('json', (value, c) => {
    const parsed = linkSchema.safeParse(value);
    if (!parsed.success) {
      return c.json(parsed, 400);
    }
    return parsed.data as ShortLink;
  }),
  async (ctx) => {
    const data = ctx.req.valid('json');
    // Set expire_at if given, or fallback to 1 month expiry
    const expireAt = data.expire_at
      ? dayjs(data.expire_at).unix()
      : dayjs().add(1, 'month').unix();
    if (expireAt <= dayjs().unix()) {
      return ctx.json(
        { message: 'The expire_at must be greater then current date time' },
        400
      );
    }

    let key = data.key || nanoid(7);
    let exists = await ctx.env.SHORTLINKS.get(key);
    while (exists) {
      key = nanoid(7);
      exists = await ctx.env.SHORTLINKS.get(key);
    }
    await ctx.env.SHORTLINKS.put(key, JSON.stringify(data), {
      expiration: expireAt,
    });
    return ctx.json(
      { ...data, key: key, short_url: `https://idm.in/${key}` },
      200
    );
  }
);
```

### Code explanations -

This code is `POST` request to create short links. Here's a breakdown of the code to explain what all I am doing:

1. `const links = new Hono<{ Bindings: Bindings }>():` It creates an instance of the Hono object.

2. Validation with zod - The `validator('json', (value, c) => {...}):` function is used as a middleware for validating the incoming JSON payload defined in `linkSchema`.

3. Set expiration: Checks if an expiry date is provided in the payload. If not, it sets an expiry date one month from the current date and time.
        
4. Generates a unique key for the link using `nanoid(7)` or uses the provided key from the payload if available.

5. Stores the link data (converted to a JSON string) in the Cloudflare KV (`SHORTLINKS`) with an expiration time based on the calculated expiry date.
    
## Demo

The demo is available on [IDM](https://idm.in/), it's free to use and open-sourced on Github to **build your own custom URL shortener**.

![Short your links](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/khcz4xrgxyzr19ua8auq.gif)

You can clone the repo to deploy on your Cloudflare account.

[Star the repository](https://github.com/dayschedule/idm) on Github to show your support :-)