Fast and type-safe full-stack starter powered by Bun, Elysia, React, and shadcn/ui
A production-ready full-stack TypeScript template that combines the best tools in the modern JavaScript ecosystem. Built with Bun for blazing-fast development and single-binary deployment, Elysia for type-safe backend APIs, and React with shadcn/ui for beautiful, accessible user interfaces.
| Feature | Description |
|---|---|
| Bun Runtime | Fast JavaScript runtime and bundler |
| Elysia Backend | Type-safe backend framework with excellent DX |
| React 19 | Modern UI library with latest features |
| React Router 7 | Hash-based client-side routing |
| Tailwind CSS 4 | Utility-first CSS framework |
| shadcn/ui | Beautiful, accessible UI components |
| Drizzle ORM | Type-safe database ORM with SQLite |
| Better Auth | Authentication with session management |
| TypeScript | End-to-end type safety |
| Single Binary | Compile to standalone executable |
- Bun >= 1.0.0
# Clone the repository
git clone https://github.com/trexolab-solution/elysia-react-app.git
cd elysia-react-app
# Install dependencies
bun install
# Set up environment variables
cp .env.example .envStart the development server with hot reload:
bun devOpen http://localhost:1360 in your browser.
# Compile to standalone binary
bun build
# Run production build
bun start
# or run the binary directly
./build/serverThe build creates a single executable file that can be deployed anywhere - no Node.js or Bun runtime required on the target server.
elysia-react-app/
├── frontend/ # React frontend application
│ ├── assets/ # Static assets (logo, favicon)
│ │ ├── logo.png # Application logo
│ │ └── favicon.ico # Browser favicon
│ ├── pages/ # Page components
│ │ ├── home.tsx # Homepage with getting started guide
│ │ ├── about.tsx # About page with tech stack
│ │ └── features.tsx # Features showcase
│ ├── components/ # Reusable UI components
│ │ └── ui/ # shadcn/ui components
│ │ ├── button.tsx # Button component with variants
│ │ └── card.tsx # Card layout component
│ ├── hooks/ # Custom React hooks
│ │ └── title-context.tsx # Page title management
│ ├── lib/ # Utility functions
│ │ └── utils.ts # CN utility for Tailwind
│ ├── app.tsx # App entry with providers
│ ├── router.tsx # React Router configuration
│ ├── global.css # Global styles & Tailwind
│ └── index.html # HTML template
│
├── server/ # Elysia backend server
│ ├── index.ts # Server entry point
│ ├── env.ts # Environment validation (Zod)
│ ├── auth-route.ts # Better Auth routes
│ ├── lib/
│ │ └── auth.ts # Better Auth configuration
│ └── db/ # Database layer
│ ├── index.ts # Drizzle ORM setup
│ ├── schemas/ # Database schemas
│ └── migrations/ # Migration files
│
├── shared/ # Shared utilities
│ ├── logger/ # Logging system
│ └── project-metadata.ts # Project metadata
│
├── build/ # Production build output
│ └── server # Compiled binary
├── database.db # SQLite database
├── drizzle.config.ts # Drizzle configuration
└── package.json # Dependencies & scripts
This starter uses React Router 7 with hash-based routing for client-side navigation.
Routes are defined in frontend/router.tsx:
import { createHashRouter } from "react-router";
import Home from "./pages/home";
import About from "./pages/about";
import Features from "./pages/features";
export const router = createHashRouter([
{ path: "/", Component: Home },
{ path: "/about", Component: About },
{ path: "/features", Component: Features },
]);- Create a page component in
frontend/pages/:
// frontend/pages/contact.tsx
import { Button } from "@/frontend/components/ui/button";
import { ArrowLeft } from "lucide-react";
import { Link } from "react-router";
export default function Contact() {
return (
<div className="min-h-screen flex flex-col items-center justify-center p-8">
<div className="max-w-2xl w-full">
<Button variant="ghost" size="sm" asChild>
<Link to="/">
<ArrowLeft className="mr-2 h-4 w-4" />
Back to Home
</Link>
</Button>
<h1 className="text-3xl font-bold mt-6">Contact Us</h1>
{/* Your content here */}
</div>
</div>
);
}- Add the route to
frontend/router.tsx:
import Contact from "./pages/contact";
export const router = createHashRouter([
// ... existing routes
{ path: "/contact", Component: Contact },
]);import { Link } from "react-router";
import { Button } from "@/frontend/components/ui/button";
// Basic link
<Link to="/about">About Us</Link>
// Button link
<Button asChild>
<Link to="/features">View Features</Link>
</Button>
// Programmatic navigation
import { useNavigate } from "react-router";
function MyComponent() {
const navigate = useNavigate();
return <button onClick={() => navigate("/features")}>Go</button>;
}// Router config
{ path: "/user/:id", Component: UserProfile }
// Component
import { useParams } from "react-router";
function UserProfile() {
const { id } = useParams();
return <div>User ID: {id}</div>;
}- Works with static file servers without server-side configuration
- No need for catch-all route handling on the server
- URLs look like
http://localhost:1360/#/about - Perfect for single-binary deployments
This starter uses Drizzle ORM with SQLite for type-safe database operations.
# Generate migrations from schema changes
bun db:generate
# Run pending migrations
bun db:migrate
# Open Drizzle Studio (database GUI)
bun db:studioSchemas are defined in server/db/schemas/:
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", {
id: text("id").primaryKey(),
email: text("email").notNull().unique(),
name: text("name"),
createdAt: integer("created_at", { mode: "timestamp" }).notNull(),
});This starter includes Better Auth for secure user authentication with session management.
Authentication is configured in server/lib/auth.ts and routes are handled in server/auth-route.ts.
- Session-based authentication
- Secure cookie handling
- CORS support for cross-origin requests
- TypeScript-first API
Copy .env.example to .env and configure:
| Variable | Description | Default |
|---|---|---|
NODE_ENV |
Environment mode | production |
PORT |
Server port | 1360 |
HOST |
Server hostname | localhost |
MAX_BODY_SIZE_IN_MB |
Max request body size | 200 |
DATABASE_URL |
Database connection string | ./database.db |
ALLOWED_ORIGINS |
CORS allowed origins | - |
LOG_LEVEL |
Log level (debug/info/warn/error) | info |
SESSION_SECRET |
Cookie/token signing secret | - |
JWT_SECRET |
JWT signing secret | - |
BETTER_AUTH_SECRET |
Better Auth secret | - |
BETTER_AUTH_URL |
Better Auth base URL | - |
See .env.example for all available options including SMTP, S3, Redis, and rate limiting.
| Command | Description |
|---|---|
bun dev |
Start development server with hot reload |
bun build |
Compile to standalone binary |
bun start |
Run production binary |
bun typecheck |
Run TypeScript type checking |
bun lint |
Run ESLint |
bun clean |
Remove build artifacts |
bun db:generate |
Generate database migrations |
bun db:migrate |
Run database migrations |
bun db:studio |
Open Drizzle Studio |
-
Build the application:
bun build
-
Copy
./build/serverto your server -
Set environment variables
-
Run the binary:
./build/server
No Node.js or Bun runtime required on the target server.
A docker-compose.yml is included for containerized deployments.
docker-compose up -d- Bun - JavaScript runtime & bundler
- Elysia - Backend framework
- React - UI library
- Tailwind CSS - CSS framework
- shadcn/ui - UI components
- Drizzle ORM - Database ORM
- Better Auth - Authentication
- TypeScript - Type safety
MIT
