The Problem
Every creator needs a link-in-bio page. But most options charge $12–$15/month for what is essentially a list of buttons. Small YouTubers, TikTok sellers, and artists don't need that overhead — they need something free that works, with the option to upgrade when they actually need more.
So I built LinkBio — a fully functional link-in-bio platform deployed on Vercel, powered by Next.js 16, Amazon DynamoDB, and S3.
Live app: https://linkbio-five-sigma.vercel.app
Source: https://github.com/skinmalata/linkbio
Why DynamoDB (and Why Single-Table Design)
A link-in-bio page is a textbook key-value workload. Every public page load needs four things:
- Resolve the username to a user ID
- Fetch the profile + theme
- Fetch the links
- Fetch the featured products
That's four indexed lookups. No joins, no transactions, no relational queries.
I used a single-table design with composite PK/SK keys. The schema was built around actual access patterns, not entity relationships:
| Access Pattern | PK / SK |
|---|---|
| Username lookup | USERNAME#{handle} / PROFILE |
| Profile data | USER#{userId} / PROFILE |
| User's links | USER#{userId} / LINK#{linkId} |
| User's products | USER#{userId} / PRODUCT#{productId} |
| Click redirect | LINKID#{shortId} / META |
| Click events | CLICK#{linkId} / TS#{timestamp} |
The username resolution is O(1) — no secondary index needed. Profile + links + products for a page load are fetched via three parallel Query calls with begins_with on the sort key. Each page load runs in under 10ms at the database layer.
The click event schema deserves special mention. Because the sort key is TS#{timestamp}, time-range queries for analytics charts are a native DynamoDB operation — I filter by sort key prefix instead of scanning old data. Without this design, every analytics query would degrade as a popular link accumulates thousands of clicks.
Architecture Overview
- Visitor → Next.js Server Component → DynamoDB (4 parallel queries) → Rendered page
- Click on link → /api/track/{linkId} → record event → 302 redirect
- Admin signs in with Google → Dashboard UI → CRUD via API routes
The public profile page is a Server Component — it queries DynamoDB directly, no API round-trip. The dashboard is all Client Components talking to API routes protected by NextAuth v5.
File uploads (avatars, product images) go through /api/upload → S3 → URL stored in DynamoDB.
Features
Free Tier
- Unlimited page views
- 3 links
- All 6 themes (Minimal, Dark, Forest, Ocean, Sunset, Lavender)
- Click analytics with trend charts and traffic sources
Pro Tier ($9/month via Stripe)
- Unlimited links
- Custom domains with CNAME setup guide
- Product shop (up to 10 items with images, prices, 60+ currencies)
- Advanced analytics with Recharts (LineChart + PieChart)
The Click Tracking Flow
The tracking endpoint at /api/track/{linkId} does three things in about 50ms:
- Looks up the target URL from LINKID#{linkId}
- Writes a click event to CLICK#{linkId} with timestamp, referrer, and user agent
- Redirects the browser with a 302
The analytics page queries those events grouped by day for trend charts and by referrer for the source breakdown. Referrers are categorized (Google, Twitter, YouTube, Direct, etc.) so the pie chart is immediately useful instead of showing raw URLs.
What Shipping Taught Me
A friend in a creator Discord was the first real user. She runs a small sticker shop on Etsy and set up her page in about 90 seconds. Her feedback was exactly what I needed: the themes are genuinely good (Forest and Sunset are the most-used), the shop integration makes sense for her use case, and the free tier doesn't feel like a trial.
What she wants most is drag-to-reorder for links. The links are stored with a position integer and sorted on retrieval, but there's no drag UI yet. It's the next thing I'm building.
Tech Stack
Next.js 16, TypeScript, Tailwind CSS 4, Amazon DynamoDB (single-table), Amazon S3, NextAuth v5 (Google OAuth), Stripe, Recharts, deployed on Vercel.
Try LinkBio Free
No credit card required. Get your link-in-bio page set up in under 2 minutes.
Visit LinkBio → View Source on GitHubBuilt for the #H0Hackathon. If you're building something similar or have feedback, I'd love to hear it on GitHub: https://github.com/skinmalata/linkbio