I built an URL shortener with Cloudflare KV
Vikash Rathee
Posted on December 9, 2023
I am building an open source, highly scalable, and low-cost URL shortener with Cloudflare KV
By low-cost I mean, just $5 per month on Cloudflare worker and a free plan for basic requirement -
Idea
At DaySchedule, 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 but also customization options, analytics, and scalability, all while maintaining a significantly lower cost compared to our established services on AWS.
Features
-
Expirable links using
cacheTtl
option on KV - Custom domain using Cloudflare for SaaS
- Analytics using Worker analytics
API
I used 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 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:
const links = new Hono<{ Bindings: Bindings }>():
It creates an instance of the Hono object.Validation with zod - The
validator('json', (value, c) => {...}):
function is used as a middleware for validating the incoming JSON payload defined inlinkSchema
.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.
Generates a unique key for the link using
nanoid(7)
or uses the provided key from the payload if available.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, it's free to use and open-sourced on Github to build your own custom URL shortener.
You can clone the repo to deploy on your Cloudflare account.
Star the repository on Github to show your support :-)
Posted on December 9, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.