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
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.
cacheTtl
option on KV
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
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
);
}
);
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.validator('json', (value, c) => {...}):
function is used as a middleware for validating the incoming JSON payload defined in linkSchema
.nanoid(7)
or uses the provided key from the payload if available.SHORTLINKS
) with an expiration time based on the calculated expiry date.
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.