DEV Community

Cover image for I Built a Full-Stack React Framework on Bun at 18. Here's Why Next.js Was Doing Too Much.
Abdelkabir Ouadoukou
Abdelkabir Ouadoukou

Posted on

I Built a Full-Stack React Framework on Bun at 18. Here's Why Next.js Was Doing Too Much.

I built x — an open-source, ultra-fast full-stack React framework designed from scratch to run natively on the Bun runtime in a single process. Here is why I built it, how it works, and what I learned along the way.


💡 The Realization: Modern Web Frameworks Are Bloated

Most modern React frameworks ship with an overwhelming amount of abstraction: a separate build step, a complex dev server, heavy bundlers, independent API layers, and endless configuration files. By the time you run npm install, your node_modules folder already holds hundreds of megabytes of dependencies you'll never touch directly.

When I started diving deep into Bun, everything changed. Bun isn’t just a JavaScript runtime — it’s a transpiler, bundler, test runner, package manager, and native HTTP engine with built-in SQLite and Postgres support. It starts in single-digit milliseconds.

I asked myself a simple question: If Bun already does all of this natively, why are we still wrapping React around Webpack, Vite, or complex Node.js polyfills?

So, at 18, I decided to build x.


⚡ What is x?

x is a full-stack React meta-framework built natively for Bun. Not "Bun-compatible" — actually built on top of Bun’s core primitives (Bun.serve(), Bun.file(), and Bun's native bundler).

No Webpack. No Vite. No esbuild overhead. Just Bun and React executing in a single, blazing-fast process.


🔑 Key Architecture & Features

Here is what x gives you out of the box with zero configuration:

  • 📁 File-Based Routing: Simply drop .tsx files in src/pages/ to instantly create routes.
  • Hybrid Rendering (Static vs. SSR): Choose per-route rendering with a single line: export const mode = "static".
  • 🔌 Built-in API Routes: Handle HTTP methods (GET, POST, PUT, DELETE) in src/api/*.ts without a separate backend server.
  • 🛠️ RPC Server Functions: Call type-safe server-side logic directly from your components without writing REST boilerplate.
  • 🏝️ Islands Architecture: Selective hydration ensures near-zero JavaScript shipped to the client by default.
  • 📚 Content Collections: First-class Markdown & Frontmatter support with automatic route generation and syntax highlighting via Shiki.
  • 🗄️ Integrated Data Layer: Native SQLite & PostgreSQL bindings with embedded versioned migrations.
  • 🛡️ Zero-Trust Security: Built-in CSRF verification, rate limiting, secure HTTP headers, and strict build-time environment variable isolation.

⏱️ The 30-Second Quickstart

You can bootstrap and launch a production-grade x application in under 30 seconds:

bun create thexjs-app@latest my-app
cd my-app
bun run dev

Enter fullscreen mode Exit fullscreen mode

Your app is live at http://localhost:3000 with hot-module reloading enabled out of the box!


🧪 Show Me The Code

1. Minimal Static Page

Every page in x is a React component. Here is how simple a prerendered static page is:

// src/pages/index.tsx
import type { RouteProps } from "@thexjs/core";

export const mode = "static";

export default function HomePage({}: RouteProps) {
  return (
    <main className="max-w-xl mx-auto py-12">
      <h1 className="text-4xl font-bold">Hello from x!</h1>
      <p className="mt-2 text-gray-600">Built natively on the Bun runtime.</p>
    </main>
  );
}

Enter fullscreen mode Exit fullscreen mode

2. SSR Page with Server Loaders

Need fresh server data on every request? Export an async loader function:

// src/pages/products/[id].tsx
import type { RouteProps, LoaderArgs } from "@thexjs/core";

export async function loader({ params }: LoaderArgs) {
  const product = await db.query("SELECT * FROM products WHERE id = ?", [params.id]);
  if (!product) throw new Response("Not Found", { status: 404 });
  return { product };
}

export default function ProductDetail({ loaderData }: RouteProps<typeof loader>) {
  return (
    <div>
      <h1 className="text-3xl font-bold">{loaderData.product.name}</h1>
      <p className="text-xl text-green-600">${loaderData.product.price}</p>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

3. Server Functions (No REST Boilerplate)

Execute server code straight from your UI components:

// src/actions/subscribe.ts
export async function subscribeUser(email: string) {
  if (!email.includes("@")) throw new Error("Invalid email");
  await db.execute("INSERT INTO subscribers (email) VALUES (?)", [email]);
  return { success: true };
}

Enter fullscreen mode Exit fullscreen mode
// src/components/Form.tsx
import { subscribeUser } from "../actions/subscribe";

// Calling it directly like a standard async function
const res = await subscribeUser("dev@example.com");

Enter fullscreen mode Exit fullscreen mode

🛡️ Enterprise Security Out-of-the-Box

Building a framework means taking security seriously. x ships with opinionated security defaults:

  • Build-Time Public Env Leak Detector: During x build, the compiler AST-scans every client bundle. If server secrets like DATABASE_URL or STRIPE_SECRET_KEY sneak into client files, the build halts instantly:
[x] ERROR: Server-only environment variable(s) leaked into client bundle:
    - DATABASE_URL
    - STRIPE_SECRET_KEY

Enter fullscreen mode Exit fullscreen mode

Only variables prefixed with THEXJS_PUBLIC_* are permitted in browser bundles.

  • Native CSRF & Rate Limiting: All dynamic actions undergo Origin & Referer verification, paired with a configurable sliding-window rate limiter (60 req/min default).
  • Production Security Headers: Content Security Policy (CSP), HTTP Strict Transport Security (HSTS), and X-Frame-Options are injected at the HTTP engine layer.

📦 Deployment: Ship Anywhere Bun Runs

Building your app generates a lean, self-contained output directory inside .x/:

x build

Enter fullscreen mode Exit fullscreen mode
.x/
├── client/       # Prerendered HTML, isolated island JS chunks, static assets
└── server/
    └── index.js  # Optimized single-file Bun server entry

Enter fullscreen mode Exit fullscreen mode

Deploy the output to Fly.io, Railway, Docker, or any VPS. You can also use the official Vercel adapter for serverless edge deployment:

bun add -d @thexjs/adapter-vercel
x build --adapter vercel
vercel deploy --prebuilt

Enter fullscreen mode Exit fullscreen mode

🎯 What Building x Taught Me

Building a full-stack framework at 18 wasn’t just about writing code — it was about understanding system architecture, bundler internals, AST parsing, state hydration, and developer experience.

It proved to me that simplicity is the ultimate sophistication. We don’t need heavier tools to build better websites; we just need better integration with the low-level primitives we already have.


🌟 Join the Journey

x is 100% open-source under the MIT License, complete with documentation and starter templates.

If you believe the future of web development should be faster, simpler, and built natively on modern runtimes, give the repository a ⭐ Star on GitHub and try building your next project with x!

Top comments (1)

Collapse
 
abdelkabirouadoukou profile image
Abdelkabir Ouadoukou

Whats ur feedback