Full Stack Template

The full-stack template provides everything you need to build a complete web application with authentication, database, and a modern React frontend.

Features

  • React Frontend with Vite and TanStack Router
  • Hono API with type-safe RPC
  • Cloudflare D1 database with Drizzle ORM
  • Better Auth with Discord OAuth
  • Type-safe API client auto-generated with Orval
  • Tailwind CSS for styling
  • Vitest for testing

Quick Start

npm create vinoflare@latest my-app

Or skip the prompts:

npm create vinoflare@latest my-app --type=full-stack --yes

Project Structure

Key Files

import { createRouter } from "@tanstack/react-router";
import { routeTree } from "@/generated/routeTree.gen";
 
const router = createRouter({ routeTree });
 
// Type-safe routing throughout your app
export function createApp() {
  const app = new Hono<AppBindings>();
  
  // Middleware
  app.use(database());
  app.use(jsonLogger());
  app.use(authGuard());
  
  // Routes
  app.route("/api", apiRouter);
  
  return app;
}
import { sqliteTable, text } from "drizzle-orm/sqlite-core";
 
export const users = sqliteTable("users", {
  id: text("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name"),
});

Development Workflow

1. Start Development Server

npm run dev

This starts:

  • Vite dev server on port 5173
  • Wrangler on port 8787
  • File watchers for type generation

2. Create a New Module

npm run gen:module posts

This generates:

  • Database table schema
  • API routes and handlers
  • TypeScript types
  • Test files
  • Frontend hooks

3. Run Tests

npm run test

4. Build for Production

npm run build
npm run deploy

Authentication Setup

  1. Create a Discord application at https://discord.com/developers
  2. Add OAuth redirect: http://localhost:8787/api/auth/callback/discord
  3. Update .dev.vars:
DISCORD_CLIENT_ID=your-client-id
DISCORD_CLIENT_SECRET=your-client-secret
BETTER_AUTH_SECRET=your-secret-key

Database Migrations

# Create a new migration
npm run db:generate
 
# Apply locally
npm run db:push:local
 
# Apply to production
npm run db:push:prod

Type Generation

Types are automatically generated for:

  • Routes - TanStack Router types
  • API Client - Orval generates typed fetch functions
  • Database - Drizzle generates table types
  • Environment - Wrangler generates CloudflareBindings

Run manually with:

npm run gen:types
npm run gen:routes
npm run gen:api

Deployment

Deploy to Cloudflare Workers:

npm run deploy

Set production secrets:

wrangler secret put DISCORD_CLIENT_ID
wrangler secret put DISCORD_CLIENT_SECRET
wrangler secret put BETTER_AUTH_SECRET

Best Practices

  1. Module Organization - Keep related code together in modules
  2. Type Safety - Let TypeScript guide your development
  3. Testing - Write tests for critical paths
  4. Environment Variables - Never commit secrets
  5. Database Migrations - Always use migrations for schema changes

Common Tasks

Add a New Page

Create a new file in src/client/routes/:

// src/client/routes/about.tsx
import { createFileRoute } from "@tanstack/react-router";
 
export const Route = createFileRoute("/about")({
  component: AboutPage,
});
 
function AboutPage() {
  return <h1>About Us</h1>;
}

Add an API Endpoint

Create a new route in src/server/modules/:

// src/server/modules/posts/posts.routes.ts
import { createRouter } from "@/server/core/api-builder";
 
export const postsRouter = createRouter()
  .get("/", { 
    handler: async (c) => {
      return c.json({ posts: [] });
    }
  });

Query the Database

import { db } from "@/server/db";
import { posts } from "@/server/db/schema";
 
const allPosts = await db.select().from(posts);

Troubleshooting

  • Types not updating? Run npm run gen:types
  • Database errors? Check migrations with npm run db:push:local
  • Auth not working? Verify Discord credentials in .dev.vars
  • Build failing? Ensure all dependencies are installed

Next Steps