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 customers upvote a URL shortener feature with auto-expirable links to book an appointment instead of 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 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 custom URL shortener.
You can clone the repo to deploy on your Cloudflare account.
Donโt forget to Star the repository on GitHub to show your support :-)
Also published here.