I'm not from a big tech company. I haven't worked at Google, Meta, or any of the places that make your resume impressive. I'm just a developer who learned by building things and breaking them.
Anyone can write articles about technology. I could tell you about React Server Components, edge computing, and type-safe APIs without ever building anything real. The internet is full of that—tutorials written by people who've never shipped the stack they're explaining.
But here's the thing: this website isn't just words. It's proof.
Every pattern I write about is running in production right now. The authentication system handling your session. The content pipeline compiling this article. The API serving comments. The monitoring catching errors before you see them. This site is built with everything I'm about to explain.
If the explanations don't make sense, the site wouldn't work. If the architecture was wrong, you'd notice—slow loads, broken features, bugs. The fact that it runs smoothly is the validation.
So yes, this is a personal website. But it's also a working answer to the question every developer faces: "Can you actually build this, or are you just good at talking about it?"
What Changed
Two years ago, my portfolio was a monolithic Next.js app doing everything. Authentication lived in API routes. The blog was stored in a database. Comments were a custom-built system I regretted maintaining.
It worked, but every feature felt like fighting the architecture.
The shift happened when I split concerns properly. Frontend as a Next.js app. Backend as a Cloudflare Worker. Content as static MDX files compiled at build time. Each piece does one thing well.
The Honest Context
Before diving into the stack, understand this: I learned these tools by building with them, not by working at companies that pioneered them. I don't have stories about "when we scaled to 10 million users at X company." I have stories about reading documentation, hitting walls, and figuring out workarounds.
This makes my perspective different. I can't tell you how these tools perform at Google-scale because I've never operated at Google-scale. What I can tell you is how they work for someone building a real site without a DevOps team, without on-call engineers, without unlimited infrastructure budget.
The constraints are different. The solutions are different. And honestly, that's more useful for most developers than hearing how Netflix optimized their CDN.
So when I explain why I chose each piece of this stack, it's not because I read about it in an architecture blog. It's because I tried the alternatives, hit specific problems, and found what actually worked for one person maintaining a production site.
The Stack I Actually Use
| Layer | Technology |
|---|---|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS v4, shadcn/ui |
| Backend | Hono, Cloudflare Workers, oRPC, Drizzle ORM, Neon PostgreSQL |
| Auth | Better Auth (email/password + GitHub OAuth) |
| Content | Velite, MDX, Shiki (dual theme), remark-gfm |
| UI | @base-ui/react, cmdk, Sonner, @tabler/icons-react |
| Data Fetching | @orpc/tanstack-query (TanStack Query) |
| Monitoring | Sentry (both web and server) |
| Build | Turborepo, Biome, lefthook, git-cliff |
That's everything. No hidden complexity. No "we'll figure this out later" pieces.
Why Next.js 16
I've shipped projects in Vue, Nuxt, SvelteKit, and plain React. Next.js won for one reason: Server Components actually work now.
React 19's Server Components aren't a gimmick. They let me fetch data without waterfalls, stream content without loading states, and keep client JavaScript minimal. The portfolio pages? Mostly server-rendered. The interactive bits? Client components where they matter.
App Router felt half-baked in Next.js 13. By version 16, the sharp edges are gone. Route groups, parallel routes, and server actions work predictably. I don't fight the framework anymore.
What sold me: async route params. No more useEffect chains to handle dynamic routes. Just await params and the data is there. Clean, obvious, fast.
No loading states. No race conditions. Just data.
Why Cloudflare Workers for the Backend
I tried keeping everything in Next.js API routes. It worked until I needed authentication, database connections, and rate limiting. Then it became a tangle of serverless functions fighting cold starts.
Cloudflare Workers solved three problems at once:
Edge performance. Workers run globally. Users in Tokyo get the same sub-50ms response as users in San Francisco. Neon PostgreSQL has edge-optimized connections via Drizzle ORM. The database isn't a bottleneck.
Cost. The free tier covers 100,000 requests per day. I've never hit it. Workers scale to zero when idle. No always-on server costs.
Simplicity. Hono feels like Express but modern. Middleware is straightforward. oRPC gives me end-to-end type safety between the frontend and backend. No GraphQL schemas. No API documentation drift. Just TypeScript all the way down.
A real API route from this site:
The frontend imports the type contract. TanStack Query handles the data fetching. Changes to the backend break at compile time, not runtime.
The Content Pipeline: Velite + MDX
I've tried every content setup: WordPress, Contentful, Sanity, storing MDX in a database, storing JSON in the repo. They all had friction.
Velite is the simplest content pipeline I've found. MDX files live in content/. Velite compiles them at build time into typed JSON. The app imports content via an alias. No API calls. No hydration mismatches. Just static data.
Here's the setup:
Now in the app:
No database queries. No API latency. No cache invalidation. Just files.
Shiki handles syntax highlighting with dual themes—light and dark mode—rendered at build time. The output is static HTML with CSS classes. No client-side JavaScript for code blocks. Fast, accessible, and works with JavaScript disabled.
Why Better Auth
I've implemented auth with NextAuth, Clerk, Supabase Auth, and custom JWT setups. Better Auth is the first one that felt obvious.
It's email/password and GitHub OAuth out of the box. No vendor lock-in. No magic APIs that break on major version bumps. Just session management, CSRF protection, and password hashing done correctly.
The setup is under 50 lines:
Avatar uploads go to Cloudflare R2. Comments use a rate limiter from Native Rate Limiting, a new feature in Cloudflare Workers it was designed to be fast. Sessions are stored in PostgreSQL. Everything is self-hosted. No third-party service can deprecate my auth flow.
What I Refuse to Use
Next.js API routes for anything complex. They're fine for simple endpoints. But once you need middleware, rate limiting, or database connections, move to a proper backend. Workers let me structure the API like a real application.
CSS-in-JS. I tried styled-components, Emotion, and Stitches. They all add runtime overhead and hydration complexity. Tailwind v4 with CSS variables is faster, simpler, and works without JavaScript.
A CMS. Every CMS I've used eventually becomes a bottleneck. Either it's slow, or the API changes, or the free tier runs out. MDX files in the repo mean I own the content. Git is the CMS. Push to deploy.
Client-side data fetching for static content. If the data doesn't change per-user, fetch it on the server. React Server Components made this obvious. The blog posts? Server-rendered. The project pages? Server-rendered. Only the comment form needs client-side state.
The Monorepo Structure
This is a Turborepo monorepo with two apps:
Why split them? Because they deploy independently. The frontend goes to Vercel. The backend goes to Cloudflare. A change to one doesn't require redeploying the other.
Turborepo handles the build pipeline:
Biome lints and formats both apps. A single biome.json at the root. No fighting ESLint and Prettier configs across workspaces.
Shared types live in the server's contract file. The frontend imports them via a path alias:
Cross-app type safety without publishing internal packages. Just TypeScript path resolution.
The Tooling That Makes It Work
Biome replaces ESLint and Prettier. One tool, one config file, 100x faster. The lint runs in milliseconds. I actually run it on save instead of skipping it.
lefthook handles Git hooks. Pre-commit runs Biome, sorts package.json scripts, and validates commit messages via commitlint. No husky, no custom scripts. Just YAML configuration.
git-cliff generates changelogs. It reads conventional commits and bumps versions automatically. The release process is bun run release, and it handles everything: version bump, changelog, git tag, push with tags.
Sentry for both apps. Errors on the frontend and backend go to the same dashboard. I know when something breaks before users report it.
The entire dev environment starts with bun run dev. Turborepo spins up the Next.js dev server, the Wrangler dev server for Workers, and Velite in watch mode. Hot reload works. Types update instantly. I don't think about the build process.
What I'm Still Figuring Out
Image optimization. Next.js Image component works well for uploaded images, but I'm still deciding between Cloudflare Images and keeping everything in R2 with manual optimization.
Comment moderation. The comment system works, but I'm manually reviewing reports. An automated spam filter would save time, but I haven't found one that doesn't require a third-party API.
Edge caching strategy. Some pages could be cached at the edge for hours. Others need to be fresh. I'm still tuning the cache headers and revalidation logic.
The Real-World Test
This site handles:
- Blog posts with syntax highlighting, dual themes, and MDX components
- Project showcase with dynamic routing and OG image generation
- Authentication with email/password and GitHub OAuth
- Comments with moderation, rate limiting, and avatar uploads
- Legal pages with versioned content tracked over time
It deploys in under two minutes. Lighthouse scores are 95+ across all metrics. The bundle size is under 100KB gzipped. First Contentful Paint is under 1 second on 3G.
More importantly, I can add features without rewriting infrastructure. Adding a new Velite collection takes five minutes. Adding a new API route is one file. Authentication changes don't cascade through the app.
Why This Matters
Look, I could have written this entire article without building anything. Copy some code examples from documentation, string together some buzzwords, call it a day. That's what makes technical writing easy to fake.
But the website you're reading this on? It's the proof I'm not faking it.
Everything described here is running in production. The Next.js 16 setup with Server Components. The Cloudflare Workers API with edge performance. The Velite content pipeline compiling MDX at build time. The Better Auth system handling sessions. The oRPC contract giving end-to-end type safety. The Turborepo monorepo coordinating deploys.
It's not impressive because of the stack. It's impressive because it actually works—and keeps working—without constant firefighting.
I'm not from FAANG. I don't have the credentials that make people trust you immediately. What I have is this: a site that handles authentication, comments, content, monitoring, and analytics without breaking. Built by one person. Maintained without burning out.
That's the validation that matters. Not the resume. Not the Medium follower count. The working software.
This stack isn't perfect. It's not revolutionary. It's just what a regular developer can build when they stop chasing trends and start shipping.
And you're looking at the proof right now.