A modern, type-safe fullstack framework for building Vue 3 + Elysia applications with zero configuration. Features automatic route discovery, single-port deployment, and end-to-end TypeScript support.
Published packages:
bev-fsβ runtime framework (v1.0.0+)create-bev-fsβ CLI scaffolding tool (v1.0.0+)
β¨ Directory-Based Routing β Your folder structure defines both API and page routes
π Type-Safe End-to-End β Shared TypeScript types from server to client
β‘ Zero Configuration β No route files, no config, just create files
π― Single-Port Deployment β One process serves frontend + backend
π₯ Hot Module Replacement β Instant feedback during development
π¦ Production Ready β Optimized builds with Vite and Bun
packages/frameworkβ Core runtime (server, client, shared utilities)packages/cliβ Project scaffolding CLI toolpackages/cli/src/templateβ Starter template with examples- Single Elysia process serves both frontend and API on port 3000
- Config flexibility β YAML and .env support with environment injection
- Middleware system β Extensible request/response pipeline
npx create-bev-fs@latest my-project
cd my-project
bun install
bun run devThen open:
- http://localhost:5173 β Vite dev server (hot reload)
- http://localhost:3000 β Production server (after build)
my-project/
βββ src/
β βββ client/ # Vue 3 frontend
β β βββ router/ # Auto-discovered pages
β β βββ api.ts # Type-safe API client
β β βββ main.ts # App entry point
β βββ server/ # Elysia backend
β β βββ router/ # Auto-discovered API routes
β β βββ store.ts # In-memory data store
β β βββ index.ts # Server entry point
β βββ shared/
β βββ api.ts # Shared TypeScript types
βββ vite.config.ts # Vite configuration
βββ package.json
βββ bunfig.toml
# Create the file
mkdir -p src/client/router/about
echo '<template><h1>About</h1></template>' > src/client/router/about/index.vueβ
Page automatically available at /about
# Create the directory and handler
mkdir -p src/server/router/users// src/server/router/users/index.ts
export const GET = () => {
return { users: [{ id: 1, name: 'John' }] }
}β
API automatically available at GET /api/users
The root package.json provides convenient scripts for development and publishing:
| Script | Description |
|---|---|
bun run bootstrap |
Install all dependencies in workspace |
bun run dev |
Build packages and start testbed with dev servers |
bun run start |
Build packages and start testbed with production server |
bun run publish |
Build both packages and publish to npm |
# Install dependencies
bun run bootstrap
# Build everything and start dev servers
bun run dev
# Now: Vite on http://localhost:5173, Elysia on http://localhost:3000Update versions in both packages/framework/package.json and packages/cli/package.json, then:
# Build and publish both packages to npm
bun run publishThis runs the publish.sh script which:
- Builds the framework package
- Builds the CLI package
- Publishes both to npm
Server (API) routes:
src/server/router/
βββ product/
β βββ index.ts β GET/POST /api/product
β βββ [id]/
β βββ index.ts β GET/PATCH/DELETE /api/product/:id
β βββ progress/
β βββ index.ts β GET/POST /api/product/:id/progress
Client (Page) routes:
src/client/router/
βββ index.vue β /
βββ product/
β βββ index.vue β /product
β βββ [id]/
β βββ index.vue β /product/:id
βββ not-found/
βββ index.vue β 404 catch-all
- Development: Vite dev server (5173) + Elysia API (3000)
- Production: Single Elysia process (3000) serves both static files and API
// src/shared/api.ts β Shared between client and server
export interface Product {
id: number
name: string
price: number
}
export namespace ProductAPI {
export interface CreateRequest {
name: string
price: number
}
export interface CreateResponse {
created: Product
}
}// src/server/router/product/index.ts
export const POST = ({ body }: any): ProductAPI.CreateResponse => {
const req = body as ProductAPI.CreateRequest
// Type-safe request and response
}// src/client/api.ts
async create(data: ProductAPI.CreateRequest): Promise<ProductAPI.CreateResponse> {
// Type-safe API client
}# .env or .env.local
SERVER_PORT=3000
SERVER_ROUTER_DIR=src/server/router
SERVER_STATIC_DIR=dist/client# config.yaml or config.yaml.local
server:
port: 3000
routerDir: src/server/router
staticDir: dist/clientPrecedence: config.yaml > .env > defaults
All config values are automatically injected into process.env with uppercase keys:
server.portβprocess.env.SERVER_PORTserver.routerDirβprocess.env.SERVER_ROUTER_DIR
- π Framework Guide β Core framework API and utilities
- π Server Guide β Building APIs with directory-based routing
- π Client Guide β Building UIs with Vue 3 and TypeScript
- π Complete Guide β Framework internals and architecture
// src/server/router/product/[id]/index.ts
import { store } from '../../../store'
export const GET = ({ params }: any) => {
const id = parseInt(params.id)
const product = store.products.find((p) => p.id === id)
return { product }
}<!-- src/client/router/product/[id]/index.vue -->
<template>
<div v-if="product">
<h1>{{ product.name }}</h1>
<p>${{ product.price }}</p>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { productAPI } from '../../../api'
const route = useRoute()
const product = ref(null)
onMounted(async () => {
const id = parseInt(route.params.id as string)
const response = await productAPI.getById(id)
product.value = response.product
})
</script>This is a monorepo containing:
- Framework package (
packages/framework) β Core runtime - CLI package (
packages/cli) β Scaffolding tool - Template (
packages/cli/src/template) β Starter project
Quick test (recommended):
# Clone repo
git clone https://github.com/kamil5b/bev-fs
cd bun-fullstack
bun install
# Build and test everything automatically
./testbed.shThe testbed.sh script builds both packages, creates a test project in /tmp/bun-testbed, links the local framework, and starts dev servers.
Manual workflow:
# Install dependencies
bun install
# Build framework
cd packages/framework
bun run build
# Build CLI
cd ../cli
bun run build
# Test locally
cd ../..
node packages/cli/dist/index.js my-test-project
cd my-test-project
bun install && bun run devMIT