Skip to content

stevepeak/kyoto-template

Repository files navigation

Template Repo

A modern, type-safe monorepo template for building full-stack applications with Next.js, tRPC, Drizzle ORM, and a Cloudflare-native background-job stack (Workflows + Queues + Durable Objects).

πŸš€ Quick Start

Prerequisites

  • Bun (v1.1.42+) - Install Bun
  • PostgreSQL Database - Use Neon, Supabase, or any PostgreSQL provider
  • Cloudflare Account - Sign up β€” Workers Paid plan is required for Workflows + Durable Objects
  • Sentry Account - Sign up for error tracking
  • PostHog Account - Sign up for analytics (optional)

Using This Template

  1. Create a new repository from this template:

    # Use GitHub's "Use this template" button, or:
    gh repo create my-app --template stevepeak/kyoto-template
  2. Clone your new repository:

    git clone <your-repo-url>
    cd my-app
  3. Install dependencies:

    bun install
  4. Set up environment variables: Create a .env file in the root directory:

    # App Configuration
    APP_URL="http://localhost:3000"
    
    # Database (PostgreSQL)
    DATABASE_URL="postgresql://user:password@host:5432/database"
    
    # Better Auth
    BETTER_AUTH_SECRET="your-secret-here"  # Generate with: openssl rand -base64 32
    
    # Cloudflare Workflows worker (replaces Trigger.dev)
    TOKEN_SIGNING_KEY="..."          # Generate with: openssl rand -base64 32
    WORKFLOWS_URL="http://localhost:8787"
    NEXT_PUBLIC_WORKFLOWS_URL="http://localhost:8787"
    
    # AI β€” routed through OpenRouter
    OPENROUTER_API_KEY="sk-or-v1-xxxxx"
    
    # Sentry (Error Tracking)
    SENTRY_DSN="https://xxxxx@sentry.io/xxxxx"
    
    # PostHog (Analytics - optional)
    POSTHOG_API_KEY="ph_xxxxx"
    POSTHOG_HOST="https://us.i.posthog.com"
  5. Set up the database:

    # Generate migration files from schema
    bun --cwd packages/db db:generate
    
    # Apply migrations to database
    bun --cwd packages/db db:migrate
    
    # Or push schema directly (for development)
    bun --cwd packages/db db:push
  6. Start development servers:

    # Start all apps (web + workflows worker)
    bun run dev
    
    # Or start just the web app
    bun run dev:web

πŸ“¦ Project Structure

kyoto-template/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ web/              # Next.js 16 web application
β”‚   β”‚   β”œβ”€β”€ app/          # App Router pages and routes
β”‚   β”‚   └── ...
β”‚   └── workflows/        # Cloudflare Workflows / Queues / DOs worker
β”‚       └── src/
β”‚           β”œβ”€β”€ workflows/        # WorkflowEntrypoint classes
β”‚           β”œβ”€β”€ durable-objects/  # Per-run progress / WebSocket fan-out
β”‚           └── queues/           # Queue consumers
β”‚
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ api/              # tRPC API definitions
β”‚   β”‚   └── src/
β”‚   β”‚       β”œβ”€β”€ index.ts  # Main router export
β”‚   β”‚       └── trpc.ts   # tRPC setup
β”‚   β”‚
β”‚   β”œβ”€β”€ db/               # Drizzle ORM database package
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”‚   β”œβ”€β”€ schema.ts # Database schema definitions
β”‚   β”‚   β”‚   └── migrate.ts # Migration runner
β”‚   β”‚   └── migrations/   # Generated migration files
β”‚   β”‚
β”‚   β”œβ”€β”€ config/           # Environment variable validation
β”‚   β”‚   └── src/index.ts  # Zod-validated config
β”‚   β”‚
β”‚   β”œβ”€β”€ agents/           # AI agent tooling and MCP integration
β”‚   β”œβ”€β”€ utils/            # Shared utilities
β”‚   └── posthog/          # PostHog analytics helpers
β”‚
└── config/               # Shared configuration
    β”œβ”€β”€ eslint/           # ESLint config
    └── tsconfig/         # TypeScript configs

πŸ›  Available Scripts

Root Level

  • bun run dev - Start all development servers
  • bun run dev:web - Start only the web app
  • bun run build - Build all packages and apps
  • bun run typecheck - Type check all packages
  • bun run lint - Lint all packages
  • bun run fix - Auto-fix linting issues
  • bun run ci - Run CI checks (typecheck + lint + knip + build)
  • bun run clean - Clean all build artifacts

Database (packages/db)

  • bun --cwd packages/db db:generate - Generate migration files
  • bun --cwd packages/db db:migrate - Run migrations
  • bun --cwd packages/db db:push - Push schema directly (dev only)
  • bun --cwd packages/db db:studio - Open Drizzle Studio

Workflows worker (apps/workflows)

  • bun --cwd apps/workflows dev - Start Wrangler dev with Workflows / Queues / DOs
  • bun --cwd apps/workflows dev:scheduled - Same, plus the /__scheduled endpoint for manual cron firing
  • bun --cwd apps/workflows deploy - Deploy the worker (Workflows + DOs + Queues + Cron triggers)
  • bun --cwd apps/workflows tail - Stream production logs

Trigger a cron run locally:

curl 'http://localhost:8787/__scheduled?cron=0+3+*+*+*'

πŸ— Tech Stack

Core

  • Bun - Fast JavaScript runtime and package manager
  • Turborepo - High-performance monorepo build system
  • TypeScript - Type-safe JavaScript

Frontend

Backend

Infrastructure

  • Sentry - Error tracking and monitoring
  • PostHog - Product analytics
  • Vercel - Deployment (configured in vercel.json)

πŸ“š Key Packages

@app/config

Centralized environment variable parsing and validation with Zod. Provides type-safe access to all environment variables across the monorepo.

import { getConfig } from '@app/config'
const { APP_URL, DATABASE_URL } = getConfig()

@app/api

Server-side tRPC API definitions. Contains all API routers and procedures with end-to-end type safety.

@app/db

Drizzle ORM database package. Contains schema definitions, migrations, and database connection logic.

import { db } from '@app/db'
import { schema } from '@app/db/schema'

@app/agents

AI agent tooling and MCP (Model Context Protocol) integration for orchestrating specialized agents.

@app/utils

Shared JavaScript utilities and helper functions.

πŸ”§ Development Guidelines

Type-Driven Development

Adjust types and schemas first before implementing logic. Run typecheck after changes:

bun run typecheck

Named Arguments

Use named arguments instead of inline arguments:

// βœ… Good
function greet(args: { name: string }) {}

// ❌ Avoid
function greet(name: string) {}

Database Migrations

  • NEVER edit files in packages/db/migrations
  • ONLY edit packages/db/src/schema.ts to make schema changes
  • Use db:generate to create migrations and db:migrate to apply them

Code Quality

  • Uses ESLint and Prettier for code formatting
  • Uses Knip for detecting unused code
  • Pre-commit hooks with Husky and lint-staged

🚒 Deployment

Vercel

The project is configured for Vercel deployment. Set all environment variables in the Vercel dashboard.

Workflows worker

Deploy the workflows Worker (Workflows + Durable Objects + Queues + Cron triggers in one shot):

bun --cwd apps/workflows deploy

Set runtime secrets once:

bunx wrangler --cwd apps/workflows secret put TOKEN_SIGNING_KEY
bunx wrangler --cwd apps/workflows secret put OPENROUTER_API_KEY
bunx wrangler --cwd apps/workflows secret put SENTRY_DSN

GitHub Actions Secrets

The CI workflow (.github/workflows/ci.yml) runs database migrations and deploys to Cloudflare on every push to main. Add the following secrets at GitHub β†’ Settings β†’ Secrets and variables β†’ Actions β†’ New repository secret:

Secret Used by Where to find it
DATABASE_URL deploy-migrations Your PostgreSQL provider's dashboard. For Neon, open the project β†’ Connection Details β†’ copy the pooled connection string. For Supabase, open Project Settings β†’ Database β†’ Connection string (URI).
CLOUDFLARE_API_TOKEN deploy-cloudflare Cloudflare dashboard β†’ My Profile β†’ API Tokens β†’ Create Token β†’ use the Edit Cloudflare Workers template (or a custom token with Account: Workers Scripts: Edit + User: User Details: Read).
CLOUDFLARE_ACCOUNT_ID deploy-cloudflare Cloudflare dashboard β†’ select your account β†’ Workers & Pages β†’ the Account ID is shown in the right sidebar (or in the URL: dash.cloudflare.com/<account-id>).
NEXT_PUBLIC_APP_URL deploy-cloudflare Public URL of the deployed app (e.g. https://kyoto-web.example.workers.dev). Inlined into the client bundle at build time.
NEXT_PUBLIC_POSTHOG_API_KEY deploy-cloudflare PostHog β†’ Project Settings β†’ Project API Key. Inlined into the client bundle at build time so the browser SDK can initialize.
NEXT_PUBLIC_POSTHOG_HOST deploy-cloudflare https://us.i.posthog.com (US cloud) or https://eu.i.posthog.com (EU). Inlined at build time.
NEXT_PUBLIC_SENTRY_DSN deploy-cloudflare Sentry β†’ Project Settings β†’ Client Keys (DSN). Inlined at build time.

You can also add them via the GitHub CLI:

gh secret set DATABASE_URL
gh secret set CLOUDFLARE_API_TOKEN
gh secret set CLOUDFLARE_ACCOUNT_ID
gh secret set NEXT_PUBLIC_APP_URL
gh secret set NEXT_PUBLIC_POSTHOG_API_KEY
gh secret set NEXT_PUBLIC_POSTHOG_HOST
gh secret set NEXT_PUBLIC_SENTRY_DSN

Cloudflare Worker runtime secrets

Server-side secrets (the ones without a NEXT_PUBLIC_ prefix β€” POSTHOG_API_KEY, SENTRY_DSN, OPENROUTER_API_KEY, BETTER_AUTH_SECRET, etc.) are read by the Worker at runtime, not inlined at build. Set them once with Wrangler from apps/web:

bunx wrangler secret put POSTHOG_API_KEY
bunx wrangler secret put POSTHOG_HOST
bunx wrangler secret put SENTRY_DSN
bunx wrangler secret put BETTER_AUTH_SECRET
bunx wrangler secret put DATABASE_URL
# ...repeat for any other required secret in packages/config/src/index.ts

The CI deploy uses wrangler deploy --keep-vars so these secrets persist across deployments.

πŸ“– Learn More

πŸ“„ License

See LICENSE file for details.

About

Vibe coding template for creating apps

Topics

Resources

License

Stars

Watchers

Forks

Contributors