Full-stack React + Python with zero configuration.
Build modern React applications powered by FastAPI, Bun, TanStack Router, and Tailwind CSS β all from a single pip install.
When building React apps with Python, you typically have two choices:
- SPA-only: An empty HTML shell, React takes over in the browser. No SEO, slow initial loads, and you still need to build a REST/GraphQL API.
- Jinja + Islands: Server-render with templates, sprinkle React for interactivity. But you're constantly juggling two mental models.
Full-stack JS frameworks like Next and TanStack have SSR, hydration, and flexible rendering modes. Vegabase brings this experience to Python β use Python for backend logic, JavaScript for rendering html.
- π Zero Config: Just install and run. Handles TS, TSX/JSX, CSS bundling with Tailwind support.
- π Python-First: FastAPI backend with Python's full ecosystem.
- βοΈ Modern React: React 19 with server-side rendering out of the box.
- β‘ Bun-Powered: Lightning-fast bundling and SSR performance.
- ποΈ Type-Safe Database: Built-in database module with Pydantic validation.
- π¨ Flexible Rendering: SSR, client-only, ISR caching, or static HTML per-page.
Requirements:
- Bun v1.0+ must be installed
- Python 3.11+
# Create a new project with uvx (no install needed)
uvx vegabase init my-app --example posts
cd my-app
uv sync && bun install
# Terminal 1: Frontend dev server
vegabase dev bun
# Terminal 2: Backend
vegabase dev pyVisit http://localhost:8000 π
| Command | Description |
|---|---|
vegabase init |
Create a new project |
vegabase dev bun |
Start Bun dev server (SSR + hot reload) |
vegabase dev py |
Start Python dev server |
vegabase build |
Build optimized production bundles |
vegabase start bun |
Start SSR server for production |
vegabase start py |
Start Python server for production |
vegabase db plan |
Preview database schema changes |
vegabase db apply |
Apply schema changes to database |
vegabase init --name my-app # Create empty project
vegabase init --name my-app --example posts # Start from posts example
vegabase init --name my-app --db sqlite # Include SQLite setup
vegabase init --name my-app --db postgres # Include PostgreSQL setupControl how each page is rendered:
from vegabase import ReactRenderer
react = ReactRenderer(app)
# Default: Server-side rendering
await react.render("Home", props, request, mode="ssr")
# Client-only: Skip SSR, render in browser
await react.render("Dashboard", props, request, mode="client")
# Cached (ISR): Cache for 60 seconds
await react.render("Posts/Index", props, request, mode="cached", revalidate=60)
# Static: Pure HTML, no JavaScript bundle
await react.render("About", props, request, mode="static")| Mode | SSR | Hydration | Use Case |
|---|---|---|---|
ssr |
β | β | Default, SEO-important pages |
client |
β | β | Dashboards, authenticated pages |
cached |
β | β | Blog posts, product pages (ISR) |
static |
β | β | Landing pages, pure content |
Built-in flash message support:
from starlette.middleware.sessions import SessionMiddleware
app.add_middleware(SessionMiddleware, secret_key="...")
react = ReactRenderer(app)
@app.post("/posts/create")
async def create_post(request: Request):
# ... create post ...
react.flash(request, "Post created!", type="success")
return RedirectResponse(url="/posts", status_code=303)Access in React:
export default function Index({ flash }) {
return (
<div>
{flash && <Alert type={flash.type}>{flash.message}</Alert>}
</div>
);
}Type-safe database queries with Pydantic validation:
from sqlalchemy import MetaData, Table, Column, Integer, String, select
from pydantic import BaseModel
from vegabase.db import Database, query
# Define schema
metadata = MetaData()
users = Table('users', metadata,
Column('id', Integer, primary_key=True),
Column('name', String),
Column('email', String),
)
# Define model
class User(BaseModel):
id: int
name: str
email: str
# Query with full type safety
db = Database("sqlite:///app.db")
with db.connection() as conn:
user = conn.one(query(User, select(users).where(users.c.id == 42)))
print(user.name) # IDE autocomplete works!
all_users = conn.all(query(User, select(users))) # Returns List[User]| Method | Returns | On Empty |
|---|---|---|
one() |
Single T |
Raises NotFoundError |
maybe_one() |
T | None |
Returns None |
many() |
List[T] |
Raises NotFoundError |
all() |
List[T] |
Returns [] |
from vegabase.db import AsyncDatabase
db = AsyncDatabase("sqlite+aiosqlite:///app.db")
async with db.connection() as conn:
users = await conn.all(query(User, select(users)))No migration files β just compare and apply:
vegabase db plan # Preview changes
vegabase db apply # Apply changesVegabase uses Dynaconf for layered configuration with environment support.
Create any of these in your project root (loaded in order, later overrides earlier):
settings.yaml # Base settings
settings.toml # Alternative format
.secrets.yaml # Sensitive values (gitignored)
settings.local.yaml # Local overrides (gitignored)
# settings.yaml
default:
DATABASE_URL: "sqlite:///app.db"
development:
DEBUG: true
production:
DATABASE_URL: "postgresql://..."Switch environments with VEGABASE_APP_ENV:
VEGABASE_APP_ENV=production python -m backend.mainfrom vegabase import settings
print(settings.DATABASE_URL)
print(settings.get("OPTIONAL_KEY", default="fallback"))All settings can be overridden via environment variables with VEGABASE_ prefix:
VEGABASE_DATABASE_URL="postgresql://..." python -m backend.mainVegabase includes structured logging out of the box:
- Request timing: Every request logs method, path, status, and duration
- Consistent format: ISO timestamps across Python and Bun servers
- Customizable: Override via
LOGGINGin your settings file
Example output:
2026-01-04T21:09:01+0000 INFO vegabase.access GET /posts 200 45ms
2026-01-04T21:09:01+0000 INFO vegabase.access POST /posts/create 303 123ms
Customize logging in settings.yaml:
default:
LOGGING:
dynaconf_merge: true # Extend defaults instead of replacing
root:
level: DEBUG# Build optimized bundles
vegabase build
# Start the SSR server (background)
vegabase start bun &
# Start the FastAPI server
vegabase start pySee the examples/ directory:
- basic-app β Minimal single-page example
- posts β CRUD app with flash messages and database
- ticketing β Full app with authentication, multi-page routing
MIT