Bun-Stack: Building a Rails-Inspired Fullstack Generator for the Bun Ecosystem
Overview
This project is a fullstack application generator that brings Rails-like productivity to the Bun runtime. Leveraging Bun's blazing-fast performance and built-in tooling, the generator creates production-ready applications with authentication, database integration, and testing infrastructure in under 30 seconds.
Live Link
Architecture
Generator Architecture
- Template System: Single-file CLI with embedded template literals for zero-dependency generation
- Project Structure: Opinionated file organization following Rails conventions with modern JavaScript patterns
- Build Pipeline: Utilizes Bun's native bundler and hot reload capabilities for instant feedback
Application Architecture
- Backend Service: Bun.serve() with file-based routing and middleware composition
- Frontend: React 18 with TypeScript, React Router, and Tailwind CSS
- Database Layer: Drizzle ORM with dual PostgreSQL/SQLite support
Technologies Used
- Runtime:
- Bun 1.0+ for JavaScript/TypeScript execution
- Native Bun APIs for password hashing, file operations, and testing
- Backend:
- File-based routing with TypeScript
- JWT authentication with CSRF protection
- Drizzle ORM for type-safe database queries
- Frontend:
- React 18 with Suspense and Error Boundaries
- React Query for server state management
- Tailwind CSS for utility-first styling
- DevOps:
- Docker with Bun's official image
- GitHub Actions for CI/CD
- Railway/Fly.io deployment support
Features
- Zero-Config Setup:
- Automatic Bun installation detection
- Database auto-configuration with fallback
- Pre-configured linting and formatting
- Authentication System:
- JWT-based authentication with secure defaults
- CSRF protection using double-submit cookies
- Protected route middleware
- Developer Experience:
- Hot reload with sub-millisecond refresh
- End-to-end type safety
- Integration testing with real HTTP requests
- Security Features:
- Content Security Policy headers
- Input validation with Zod
- SQL injection protection via parameterized queries
Development Process
Motivation and Evolution
This project emerged from the gap between Rails' productivity and modern JavaScript tooling:
- Started as an exploration of Bun's capabilities for fullstack development
- Evolved from a simple boilerplate to a comprehensive generator
- Implemented Rails-inspired conventions while embracing JavaScript ecosystem strengths
Architecture Decisions
- Bun.serve() over Express: Leveraged native performance without framework overhead
- File-based Routing over Controllers: Simplified API structure with intuitive organization
- Repository Pattern: Abstracted database operations for testability and flexibility
- Single-file CLI: Eliminated installation dependencies for instant project creation
Workflow
- Template design with escape sequences for nested template literals
- Middleware composition system for request processing pipeline
- Dual database support implementation with automatic detection
- Integration testing strategy without mocks or stubs
- Security layer implementation with modern best practices
Key Advantages
- 10x faster installation compared to npm-based generators
- Near-instant hot reload improving developer iteration speed
- Type safety from database to frontend components
- Production-ready security without configuration
Implementation Details
Template Generation
The generator uses a unique approach to handle template literals within templates:
// Template file content with escaped backticks
const serverTemplate = `
import { serve } from "bun";
const PORT = process.env.PORT || 3000;
serve({
port: PORT,
fetch: async (req) => {
return new Response(\`Hello from Bun at \${new Date().toISOString()}\`);
}
});
`;
// Write template to project
await Bun.write(path.join(projectPath, "src/server/index.ts"), serverTemplate);
Middleware Architecture
Request processing follows a composable middleware pattern:
type Middleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;
function compose(...middlewares: Middleware[]) {
return async (req: Request) => {
let index = -1;
async function dispatch(i: number): Promise<Response> {
if (i <= index) throw new Error("next() called multiple times");
index = i;
const middleware = middlewares[i];
if (!middleware) return new Response("Not Found", { status: 404 });
return middleware(req, () => dispatch(i + 1));
}
return dispatch(0);
};
}
Deployment
The generated applications are containerized with minimal overhead:
FROM oven/bun:1
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
COPY . .
RUN bun run build:css
EXPOSE 3000
CMD ["bun", "src/server/index.ts"]
Deployment is streamlined for modern platforms with automatic database URL detection and environment-based configuration.
Lessons Learned
Throughout this project, I gained valuable insights:
- Bun's Maturity: The runtime proved production-ready with excellent stability and performance
- Testing Complexity: Real integration tests without mocks revealed edge cases early
- Template Escaping: Managing template literals within templates required creative solutions
- Security Balance: Implementing security without sacrificing developer experience was challenging but achievable
Future Improvements
Planned enhancements include:
- WebSocket support for real-time features
- GraphQL option alongside REST APIs
- Admin panel generator for CRUD operations
- Background job queue with Bun's Worker API
- API documentation generation with OpenAPI
- Built-in observability with OpenTelemetry