CloudBio · Bio Link Management Tool

04/2026 ~ Present

Full-Stack Development
Database Design
Serverless
Cloudflare
Active
Featured

A self-hosted Bio Link management solution based on Cloudflare, supporting visual editing, multiple block types, and appearance customization

CloudBio · Bio Link Management Tool

Tech Stack

Hono

Lightweight and efficient web framework running on Cloudflare Workers

React 19

Frontend UI framework with SWR for data synchronization

Cloudflare Workers

Serverless edge computing platform

Cloudflare D1

Serverless SQLite database

Cloudflare R2

Object storage for image uploads and access

Cloudflare KV

Key-value cache for accelerating page rendering

Drizzle ORM

Type-safe database operations and migration management

shadcn/ui

High-quality component library based on Radix UI

Tailwind CSS

Utility-first CSS framework

dnd-kit

Drag-and-drop sorting implementation

Project Overview

CloudBio is a self-hosted Bio Link management tool, an open-source alternative similar to Linktree / Portaly. Users can freely combine text buttons, carousel banners, video players, and other block types through a visual drag-and-drop editor to create personalized Bio Link pages.

The full-stack architecture is built on Hono running on Cloudflare Workers, paired with D1 SQLite database, R2 object storage, and KV cache, delivering a complete Bio Link service with zero server maintenance cost.

Core Features

Seven Block Types

Supports text buttons (with subtitles, images, and animation effects), carousel banners, square panels, two-column grids, video players (YouTube), dividers, and rich text blocks — covering a wide range of content display needs.

Drag-and-Drop Editor

Implements Notion-style block drag-and-drop sorting using @dnd-kit, paired with a mobile simulation preview frame for real-time editing feedback.

Appearance Customization System

Supports solid color, gradient, and image background modes, with customizable button styles, fonts, and text colors, and two profile layout options: integrated and card-style. Advanced users can apply custom CSS for further adjustments.

Multi-Page Management

Supports creating multiple sub-pages under a single account, each with its own independent block configuration. Button blocks can link directly to other sub-pages, allowing users to organize more complex content structures in a tabbed manner while keeping the experience simple and intuitive.

Social Platform Integration

Built-in icons for 13 social platforms (Instagram, GitHub, LinkedIn, X, Threads, etc.) for one-click social link setup.

Image Management

Handles image uploads via Cloudflare R2, with client-side WebP compression and cropping tools to reduce bandwidth consumption and storage costs.

Drag-and-Drop Sorting Experience

Drag-and-drop sorting implemented with @dnd-kit: a quick click (within 300ms) opens the editor, while a long press enters drag mode. Mouse movement beyond 8px triggers dragging, preventing accidental interactions. Intuitive on both mobile and desktop without needing extra drag handles or mode switches.

Drag-and-drop sorting implemented with @dnd-kit: a quick click (within 300ms) opens the editor, while a long press enters drag mode. Mouse movement beyond 8px triggers dragging, preventing accidental interactions. Intuitive on both mobile and desktop without needing extra drag handles or mode switches.

Live Preview

The editor features a built-in mobile simulation preview frame where all changes are reflected in real time. What you see in the dashboard matches exactly what visitors see on the public page — no back-and-forth switching required.

The editor features a built-in mobile simulation preview frame where all changes are reflected in real time. What you see in the dashboard matches exactly what visitors see on the public page — no back-and-forth switching required.

Image Compression

Images are WebP-compressed and cropped on the client side before upload, reducing transfer size and R2 storage usage. After upload, long-term cache headers are applied for access, minimizing bandwidth from repeated requests.

Images are WebP-compressed and cropped on the client side before upload, reducing transfer size and R2 storage usage. After upload, long-term cache headers are applied for access, minimizing bandwidth from repeated requests.

Technical Architecture

Frontend

Built with React 19 alongside the shadcn/ui component library and Tailwind CSS v4 for a modern interface. Uses SWR for data synchronization, @dnd-kit for drag-and-drop interactions, and react-easy-crop for image cropping.

Backend

Uses Hono as the web framework, running on Cloudflare Workers edge computing. Cloudflare D1 (SQLite) serves as the database, R2 stores image assets, and KV caches rendered page HTML. Drizzle ORM is used for type-safe data operations.

Authentication

Custom-built JWT authentication with passwords hashed using PBKDF2-SHA256 (100,000 iterations). Sessions are managed with HttpOnly + Secure + SameSite cookies, with email whitelist-based invitation registration.

SSR Rendering

Public Bio pages use server-side rendering with results cached to KV, avoiding repeated database queries and improving load speed for visitors.

Tool Selection

The entire project is built on the Cloudflare ecosystem, and tool choices were made with that foundation in mind.

Why Hono instead of Express

Express is designed for Node.js environments and requires an additional compatibility layer to run on Cloudflare Workers, which compromises both performance and compatibility. Hono was built from the ground up for edge computing environments, natively supporting the Workers Request / Response API without any conversion overhead. Its routing system and middleware design are intuitive — the developer experience is similar to Express, but without any compatibility concerns.

Why D1 instead of other databases

For the same reason as choosing Hono — since the entire architecture runs on Cloudflare, D1 is the most natural database pairing. D1 is Cloudflare’s native SQLite service with zero-latency connections to Workers, eliminating the need to manage connection pools or cold start issues typical of external databases. Combined with Drizzle ORM for type-safe data operations and migration management, the development workflow is smooth and efficient.

R2 + KV Division of Responsibility

R2 handles persistent storage of static assets like images, while KV caches rendered page HTML. Each serves a distinct role: R2 handles large files, KV handles small data with high read frequency. Both are native Cloudflare services requiring no additional setup or maintenance.

Database Design

Uses Cloudflare D1 (SQLite) with Drizzle ORM, covering users, pages, block content, and appearance settings across four tables. Blocks use a JSON config field to store type-specific configuration data, enabling a flexible polymorphic block architecture.

TableDescriptionKey Fields
usersUser accounts and personal informationid, email, username, password_hash, display_name, bio, avatar_url, social_links
pagesMulti-page management supporting home and sub-pagesid, user_id, slug, title, sort_order, is_default
blocksBio page content blocks (seven types)id, user_id, type, config (JSON), is_active, sort_order
appearancesUser appearance and theme settingsid, user_id, background, button_style, font_family, text_color, custom_css

Database Design Details

JSON Config Polymorphic Design

Different block types require very different attributes: buttons need links, subtitles, and animation effects; carousel banners need multiple images and label settings; videos only need a YouTube URL. Creating a separate table or adding numerous nullable columns for each type would make the database difficult to maintain. Instead, the blocks table only retains common fields (type, is_active, sort_order), with all type-specific configuration stored in a single config JSON field. Adding a new block type only requires defining a new Config interface and default values — no database schema changes needed.

Fractional Sort Order

Drag-and-drop sorting uses a floating-point sortOrder rather than integer indices. When moving a block from position A to between B and C, the new sortOrder is (B + C) / 2. This means each reordering only requires updating a single record, without renumbering the entire list. Even after many sorting operations, floating-point precision is more than sufficient for real-world usage.

Multi-Page Support

The pages table uses the slug field to distinguish the home page (empty string) from sub-pages, with a unique index on (userId, slug) to ensure no duplicate page paths exist for the same user. Blocks are associated with their page via pageId, and deleting a page cascades to delete all blocks beneath it.

Caching Strategy

Public Bio pages are SSR-rendered and cached to Cloudflare KV, avoiding repeated database queries on every visit.

Cache Policy

Page HTML TTL is set to 5 minutes. Visits within the cache window require no database access at all. Key formats are page:{username} and page:{username}:{slug} for home pages and sub-pages respectively.

Index Tracking and Precise Invalidation

To correctly invalidate the cache when a user updates content, the system maintains a pages-idx:{username} index that records all cached sub-page slugs for that user. This allows all keys to be found and cleared at once via the index when a full invalidation is needed, without guessing or scanning. Modifying a single block only invalidates the cache for that block’s associated page, avoiding unnecessary full invalidations.

API Design

RESTful API designed with Hono routing, with all authenticated endpoints protected by JWT Middleware:

Authentication /api/auth

User registration and login, JWT token issuance and verification

Profile /api/profile

Update and manage display name, bio, avatar, and social links

Block Management /api/blocks

CRUD operations for all seven block types and drag-and-drop sort order updates

Appearance Settings /api/appearance

Save and retrieve background, button, font, color, and custom CSS settings

Image Upload /api/upload

Upload images to R2, served via /api/img/* with long-term cache headers

Public Page /api/bio/:username

Unauthenticated public endpoint for visitors to retrieve a user’s Bio page data