A fully serverless, edge-native URL shortener built on Cloudflare’s global infrastructure — leveraging Workers, KV, and Pulumi to deliver blazing-fast redirection with minimal vendor lock-in.
Curious about what’s coming next? 📍 Check out the project roadmap for planned features, enhancements, and priorities.
url-shortener/
├── apps/
│ ├── web/ # Cloudflare Worker (React SPA + API routes)
│ ├── redirector/ # Cloudflare Worker (GET /\:code → reads from KV, redirects)
├── packages/
│ ├── schema/ # Shared Zod schemas for validation, enabling end-to-end type safety
│ └── ui/ # Shared component library (shadcn/ui)
├── infra/pulumi/ # IaC: DNS, KV, routing
├── .github/workflows/ # CI/CD with GitHub Actions
├── turbo.json # Turborepo configuration
- Node.js (see
package.jsonengines field) - pnpm (e.g.,
[email protected]as perpackageManager)
# Install dependencies
pnpm install
# Start all services locally
pnpm dev| Layer | Tech |
|---|---|
| Frontend | React, Vite, Tailwind CSS, @workspace/ui (shadcn/ui) |
| Backend | Cloudflare Workers (web, redirector) |
| Validation | Zod (@workspace/schema) |
| Storage | Cloudflare KV (eventually consistent, edge-distributed) |
| Infra-as-Code | Pulumi (TypeScript, Cloudflare provider) |
| DevOps | GitHub Actions, Wrangler CLI, Turborepo |
| Deployment | Cloudflare Workers, DNS, TLS |
- Single Cloudflare Worker that serves both:
- Frontend: Vite-powered React SPA
- Backend: API routes for URL shortening (e.g.,
POST /api/short-link)
- Replaces the previous
url-creatorWorker - Uses
assets.not_found_handling: "single-page-application"for SPA routing - Hosted directly on Cloudflare Workers (not Cloudflare Pages)
- UI built with
@workspace/ui - Uses
@workspace/schemafor request/response validation and typing - Designed for future backend expansion (e.g., admin, analytics)
- Cloudflare Worker at
GET https://r.${BASE_DOMAIN}/:code - Fetches the original URL from KV and redirects via HTTP 302
- Returns a custom 404 page for invalid or expired codes
- Optimized for ultra-low latency
- Tailwind + shadcn/ui-based design system
- Shared across all frontend surfaces
- Published as
@workspace/ui
-
Centralized Zod-based schemas for validation and type inference
-
Shared between frontend and backend to enforce strict contract
-
Examples:
// CreateShortLinkRequest z.object({ originalUrl: z.string().url(), customCode: z .string() .min(3) .max(20) .regex(/^[a-zA-Z0-9_-]+$/) .optional(), expiresAt: z.string().datetime().optional(), }); // ShortLink z.object({ shortCode: z.string(), originalUrl: z.string().url(), createdAt: z.string().datetime(), expiresAt: z.string().datetime().optional(), clicks: z.number().optional(), });
- Turborepo manages the monorepo
- Each Worker has its own
wrangler.jsoncfor:- Entry points
- KV bindings
- Asset/config settings
- GitHub Actions for:
- Building frontend assets
- Deploying Workers
- Running tests and linting
- Wrangler used for deploying Workers to Cloudflare
- Uses
pnpmwith workspace configuration - Shared packages (
shared,ui) managed efficiently across the repo
- Pulumi manages:
- DNS
- KV namespaces
- Worker routes
- Cloudflare Workers handle all compute logic
- Cloudflare KV provides globally distributed, edge-accessible storage
Infrastructure bindings are abstracted to make future migrations easy.
| Cloudflare | Alternative |
|---|---|
| Workers | Vercel Edge Functions, Deno Deploy, Lambda@Edge |
| KV | Upstash, DynamoDB, EdgeDB |
| Pulumi (CF) | Pulumi AWS/Azure, Terraform, CDK |
Platform bindings are abstracted — migration won’t require core rewrites.
MIT © TrungUng
