LENK.CF is an open-source URL shortener built for Vercel serverless deployment with MongoDB for persistence, Redis for caching, and a no-framework frontend. It ships with a custom-branded landing page, custom alias support, Redis-backed redirect acceleration, a lightweight PWA setup, and a small JSON API.
The current frontend uses a dark editorial design system with an animated intro sequence, SEO and GEO metadata, and a redesigned 404 experience.
- Shorten long URLs with generated short IDs.
- Create custom aliases with validation for letters, numbers,
_, and-. - Cache both
url -> shortIdandshortId -> urlin Redis to reduce database lookups. - Redirect short links with permanent
301redirects. - Serve a static landing page and error page through Vercel routing.
- Expose a simple API for creation, redirects, discovery, and listing.
- Include a minimal service worker for PWA-style asset caching.
- Ship a metadata-rich homepage with Open Graph, Twitter Card, canonical, and JSON-LD schema.
- HTML
- CSS / SCSS assets
- Vanilla JavaScript
- Service Worker
- Node.js serverless functions on Vercel
- MongoDB with Mongoose
- Redis v3 client for caching and shared utility helpers
- Vercel routing via vercel.json
- MongoDB Atlas or any reachable MongoDB deployment
- Redis Cloud or any reachable Redis instance
- The landing page at
/serves the static UI fromstatic/index.html. - A random short link is created through
GET /p/<encodedUrl>. - A custom short link is created through
POST /customwith{ url, shortId }. - Redirects are resolved through the catch-all route and served by
api/redirect.js. - MongoDB stores canonical records.
- Redis stores hot lookups to avoid repeated database reads.
- Random IDs are generated in
api/p.js. - Existing URLs are reused when already present in the database.
- Custom aliases are rejected if the alias already exists.
- Cached short IDs return immediately from Redis.
- Cache misses fall back to MongoDB.
- Missing records redirect to
/404.
- Intro loading animation that visually compresses a long URL into a short link.
- Inline result section with copy-to-clipboard support.
- Domains panel for alternate domains.
- Toast notifications for success and error states.
- Canonical URL
- Open Graph and Twitter metadata
- Geographic metadata
- JSON-LD for
WebApplicationandFAQPage
.
|-- api/
| |-- _lib/
| | |-- cache.js
| | |-- db.js
| | `-- rate-limit.js
| |-- all.js
| |-- custom.js
| |-- index.js
| |-- p.js
| `-- redirect.js
|-- models/
| `-- model.js
|-- static/
| |-- 404.html
| |-- index.html
| `-- assets/
| |-- robots.txt
| |-- script.js
| |-- styles.css
| |-- styles.scss
| `-- sw.js
|-- LICENSE
|-- README.md
|-- package.json
`-- vercel.json
- Node.js 18+
- A MongoDB database
- A Redis instance
- Vercel CLI for local serverless development
Create a .env file in the project root for local development.
DB=mongodb+srv://<user>:<password>@cluster0.xxxxx.mongodb.net/lenk-cf?retryWrites=true&w=majority
REDIS_URL=redis://default:<password>@<host>:<port>| Variable | Required | Purpose |
|---|---|---|
DB |
Yes | MongoDB connection URI used by api/_lib/db.js |
REDIS_URL |
Yes in practice | Redis connection used by cache helpers and shared Redis utilities |
Notes:
api/_lib/db.jsconnects withdbName: 'lenk-cf'.api/_lib/rate-limit.jsfalls back toredis://127.0.0.1:6379ifREDIS_URLis missing, but the app expects Redis to be available for normal operation.
This repository does not define npm scripts. Use the Vercel CLI directly.
git clone https://github.com/adithyapaib/lenk.cf
cd lenk.cfnpm installCreate .env as shown above.
npx vercel devThe app is typically available at http://localhost:3000.
npm install -g vercelvercelAdd these in the Vercel project settings:
DBREDIS_URL
vercel deployAll endpoints are served from the same Vercel deployment domain.
Returns the static homepage UI.
Returns a JSON object with server status, route hints, domains, and credits.
Example response shape:
{
"server": "online",
"end_points": [
{"/": "index.html"},
{"/p/<url>": "Creates a new shortID for the url sent or returns an existing shortID."}
],
"source": "https://github.com/adithyapaib/lenk.cf"
}Creates or reuses a short ID for a URL.
Example:
GET /p/https%3A%2F%2Fexample.com%2Fdocs%2FintroSuccess response:
"Ab3"Behavior:
- Validates the decoded URL.
- Returns a cached short ID when available.
- Reuses an existing database record for the same URL.
- Generates a 3-character ID and falls back to 5 characters if the first candidate collides.
Creates a short link with a user-specified alias.
Request:
POST /custom
Content-Type: application/json{
"url": "https://example.com",
"shortId": "myalias"
}Success response:
"myalias"Conflict response:
0Validation:
urlis required and must parse withnew URL(...).shortIdis required.shortIdmust match^[a-zA-Z0-9_-]+$.
Supports the legacy custom-link format used by the older API index.
Example:
GET /custom/https%3A%2F%2Fexample.com%3A%3A%3A69docsBehavior:
- Decodes the URL portion before
:::69. - Uses the value after
:::69as the requested custom short ID. - Returns the same success and conflict payloads as
POST /custom.
Returns all stored documents, prefixed with a count object.
Example response shape:
[
{ "numberOfShortURLS": 2 },
{ "_id": "...", "url": "https://example.com", "shortId": "Ab3" },
{ "_id": "...", "url": "https://example.org", "shortId": "docs" }
]Redirects with HTTP 301 to the original URL.
Behavior:
- Uses Redis first.
- Falls back to MongoDB.
- Redirects to
/404when no matching short ID exists. - Normalizes stored URLs by prepending
https://if a protocol is missing during redirect.
Returns the branded not-found page.
Routing is defined in vercel.json.
Key mappings:
/->static/index.html/css->static/assets/styles.css/js->static/assets/script.js/serviceworker->static/assets/sw.js/robots.txt->static/assets/robots.txt/p/...->api/p.js/customrequests are handled byapi/custom.js/all->api/all.js/api->api/index.js- catch-all fallback route ->
api/redirect.js
MongoDB documents are stored through the Mongoose model in models/model.js.
Schema:
{
url: String,
shortId: String
}There are no explicit schema indexes or uniqueness constraints at the model level right now. Uniqueness is enforced in route logic.
Redis is used by api/_lib/cache.js and shared by the route handlers.
| Cache Key | Value | TTL | Used By |
|---|---|---|---|
url:<longUrl> |
shortId |
7 days | api/p.js, api/custom.js |
shortid:<shortId> |
destination URL | 30 days | api/p.js, api/custom.js, api/redirect.js |
all |
serialized JSON array | 30 seconds | api/all.js |
Current handlers set a small set of response headers:
api/p.js:X-Content-Type-Options,X-Frame-Options,X-XSS-Protectionapi/custom.js:X-Content-Type-Options,X-Frame-Optionsapi/redirect.js:X-Content-Type-Options,Referrer-Policy
api/_lib/rate-limit.js exposes a Redis-backed helper:
getRedisClient()checkRateLimit(ip, limit = 100, windowSec = 3600)
At the moment, the helper exists but is not wired into the public route handlers. That means the repository includes rate-limit infrastructure, but requests are not currently being blocked by it.
The service worker in static/assets/sw.js is intentionally minimal.
Current behavior:
- Caches
./and/cssduring install. - Claims clients on activation.
- Does not currently implement runtime fetch handling.
The current homepage includes:
- Intro overlay animation
- Copy-to-clipboard result state
- Alternate domain panel
- Toast-based status feedback
- SEO, GEO, and social metadata
- JSON-LD structured data
The UI currently advertises these domains:
https://lenk.cfhttps://nani.cfhttps://4543.mlhttps://urml.ml
Availability depends on DNS, hosting status, and whether those domains are still pointed at the deployed project.
- No npm scripts are defined in
package.json. - The API is intentionally simple and does not include authentication.
/allexposes all stored records and should be treated carefully in public deployments.- Alias uniqueness is handled in application logic rather than database constraints.
- The rate-limit helper is present but not enforced.
- The service worker is partial rather than a full offline strategy.
curl "http://localhost:3000/p/https%3A%2F%2Fexample.com%2Fguide"curl -X POST "http://localhost:3000/custom" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","shortId":"docs"}'curl "http://localhost:3000/api"curl "http://localhost:3000/all"This project is licensed under the MIT License. See LICENSE.
- Project: Adithya Pai
- Site: https://adithyapai.com
- Source: https://github.com/adithyapaib/lenk.cf
A fast, open-source URL shortener built with Node.js, MongoDB, and Vercel serverless functions. Features Redis caching for near-instant redirects, a custom alias system, a Progressive Web App (PWA) frontend, and a simple REST API.
Client: HTML, SCSS, Vanilla JS, PWA (Service Worker)
Server: Node.js, MongoDB (Mongoose), Redis, Vercel Serverless Functions
- Node.js 18+
- MongoDB Atlas cluster
- Redis instance (e.g. Redis Cloud)
- Vercel CLI
1. Install Vercel CLI
npm i -g vercel2. Set up MongoDB Atlas
Go to MongoDB Atlas, create a cluster, and copy the Node.js connection URI.
3. Set up Redis
Create a free Redis instance at Redis Cloud and copy the connection URL.
4. Clone and install
git clone https://github.com/adithyapaib/lenk.cf
cd lenk.cf
npm i5. Create .env
DB=mongodb+srv://<user>:<password>@cluster0.xxxxx.mongodb.net/lenk-cf?retryWrites=true&w=majority
REDIS_URL=redis://default:<password>@<host>:<port>6. Run locally
vercel devApp runs at http://localhost:3000.
7. Deploy to Vercel
vercel deployAdd DB and REDIS_URL as Environment Variables in your Vercel project settings.
All endpoints are available at http://localhost:3000 locally or your Vercel domain in production.
Returns server status and a list of all endpoints.
Resolves a short ID and redirects to the original URL (301). Results are cached in Redis for 30 days.
GET /p/https%3A%2F%2Fexample.com%2Fsome%2Flong%2Fpath
| Parameter | Description |
|---|---|
encodedUrl |
Required. The long URL, encodeURIComponent-encoded. |
Returns the generated shortId as a JSON string. Cached for 7 days.
POST /custom
Content-Type: application/json
{ "url": "https://example.com", "shortId": "myalias" }
| Field | Description |
|---|---|
url |
Required. The long URL to shorten. |
shortId |
Required. Your custom alias (letters, numbers, hyphens, underscores). |
Returns the shortId string on success, or 0 if the alias is already taken. Cached for 30 days.
Returns all documents in the database, prefixed with a count. Cached for 30 seconds.
Shown when a short ID doesn't exist in the database.
| Variable | Description |
|---|---|
DB |
MongoDB connection URI |
REDIS_URL |
Redis connection URL |
| Cache key | TTL | Used in |
|---|---|---|
shortid:<id> → URL |
30 days | redirect.js, p.js, custom.js |
url:<url> → shortId |
7 days | p.js, custom.js |
all → JSON list |
30 seconds | all.js |
- 🙋🏼♂️ Follow me on GitHub and star ⭐ this repo!
.png)