sveltekit-hono-orpc-cloudflare-starter Svelte Themes

Sveltekit Hono Orpc Cloudflare Starter

A starter Cloudflare ready kit to develop on Cloudflare utilizing Sveltekit with Fast hono api catching all api requests and with orpc

SvelteKit + Cloudflare Starter

A production-ready monorepo starter with SvelteKit, Hono, oRPC, D1 database, and type-safe everything.

Features

  • šŸš€ SvelteKit 5 with Svelte 5 runes
  • ⚔ Hono as HTTP layer (middleware, routing)
  • šŸ”· oRPC for type-safe RPC with OpenAPI generation
  • šŸ—„ļø Drizzle ORM with D1 database
  • šŸ” Session-based auth (no external deps)
  • šŸ“¦ Bun workspaces monorepo
  • ā˜ļø Cloudflare Workers deployment ready
  • šŸŽÆ Zod for validation (single source of truth)
  • šŸ”§ Interface-based DB (swap D1 for MySQL/Postgres later)

Project Structure

ā”œā”€ā”€ packages/
│   ā”œā”€ā”€ shared/              # Zod schemas, types, utilities
│   │   └── src/schemas/     # Source of truth for all types
│   │
│   └── db/                  # Database layer
│       └── src/
│           ā”œā”€ā”€ schema/      # Drizzle table definitions
│           ā”œā”€ā”€ repositories/# Data access interfaces
│           ā”œā”€ā”€ services/    # Business logic
│           └── adapters/    # D1 implementation
│
└── apps/web/                # SvelteKit app
    └── src/
        ā”œā”€ā”€ lib/
        │   ā”œā”€ā”€ rpc.ts               # Type-safe client
        │   └── server/rpc/          # Hono + oRPC
        │       ā”œā”€ā”€ context.ts       # Request context
        │       ā”œā”€ā”€ procedures.ts    # Base procedures
        │       ā”œā”€ā”€ router.ts        # Main router
        │       ā”œā”€ā”€ handler.ts       # Hono app + oRPC
        │       └── routers/         # Domain routers
        │           ā”œā”€ā”€ auth.ts
        │           └── posts.ts
        └── routes/
            └── api/[...paths]/      # All API requests

Quick Start

# Install dependencies
bun install

# Create D1 database
bunx wrangler d1 create starter-db
# Copy the database_id to apps/web/wrangler.toml

# Generate migrations
bun run db:generate

# Apply migrations locally
cd apps/web
bunx wrangler d1 migrations apply starter-db --local

# Start development server (with D1 bindings)
bun run preview

# Or start without bindings (for UI work)
bun run dev

Architecture

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                    SvelteKit Pages                      │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                         Hono                            │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │  Middleware  │  │   /api/rpc   │  │  /api/health │  │
│  │  (cors,log)  │  │    (oRPC)    │  │  (REST)      │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                      Services                           │
│              (Business logic layer)                     │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                    Repositories                         │
│               (Data access layer)                       │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                   D1 / MySQL / Postgres                 │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Key insight: Hono is the HTTP layer, oRPC is mounted on it. This gives you:

  • Hono's middleware (cors, logging, rate limiting)
  • oRPC's type-safe procedures
  • Freedom to add REST endpoints alongside RPC

Usage

Defining Procedures

// lib/server/rpc/routers/posts.ts
import { publicProcedure, protectedProcedure } from '../procedures';

export const postsRouter = {
  // Public - anyone can call
  list: publicProcedure
    .input(paginationSchema)
    .output(postsResponseSchema)
    .handler(async ({ input, context }) => {
      const postService = new PostService(context.db);
      return postService.getPublishedPosts(input);
    }),

  // Protected - requires authentication
  create: protectedProcedure
    .input(createPostSchema)
    .output(postSchema)
    .handler(async ({ input, context }) => {
      // context.user is guaranteed non-null
      const postService = new PostService(context.db);
      return postService.createPost(context.user.id, input);
    }),
};

Using the Client

// In +page.server.ts (SSR)
import { createClient } from '$lib/rpc';

export const load = async ({ fetch }) => {
  const rpc = createClient(fetch);
  const result = await rpc.posts.list({ limit: 10 });
  return { posts: result.items };  // Fully typed!
};
<!-- In +page.svelte (client-side) -->
<script lang="ts">
  import { rpc } from '$lib/rpc';

  async function createPost() {
    const post = await rpc.posts.create({
      title: 'Hello',
      content: 'World',
    });
    // post is fully typed as Post
  }
</script>

Adding Hono Routes

Need a webhook or REST endpoint? Add it directly to the Hono app:

// lib/server/rpc/handler.ts
export function createApp(locals: App.Locals) {
  const app = new Hono<Env>().basePath('/api');
  
  // ... existing setup ...

  // Add REST endpoints alongside oRPC
  app.post('/webhooks/stripe', async (c) => {
    const payload = await c.req.text();
    // Handle webhook...
    return c.json({ received: true });
  });

  // oRPC is mounted here
  app.all('/rpc/*', async (c) => { ... });

  return app;
}

API Endpoints

Endpoint Description
POST /api/rpc/auth.signUp Register new user
POST /api/rpc/auth.signIn Login
POST /api/rpc/auth.signOut Logout
POST /api/rpc/auth.me Get current user
POST /api/rpc/posts.list List published posts
POST /api/rpc/posts.listMine List my posts
POST /api/rpc/posts.create Create post
POST /api/rpc/posts.update Update post
POST /api/rpc/posts.delete Delete post
GET /api/openapi OpenAPI spec
GET /api/health Health check

Middleware Chain

// lib/server/rpc/procedures.ts

// Base procedure with context
const o = os.$context<Context>();

// Public - anyone can call
export const publicProcedure = o;

// Protected - requires authenticated user
export const protectedProcedure = o.use(async ({ context, next }) => {
  if (!context.user) {
    throw new Error('UNAUTHORIZED');
  }
  return next({ context });  // context.user now guaranteed
});

// Admin - requires admin role  
export const adminProcedure = protectedProcedure.use(async ({ context, next }) => {
  if (context.user.role !== 'admin') {
    throw new Error('FORBIDDEN');
  }
  return next({ context });
});

Commands

# Development
bun run dev              # Start dev server
bun run check            # Type check all packages

# Database
bun run db:generate      # Generate migrations from schema
bun run db:migrate       # Apply migrations

# Production
bun run build            # Build for production
bun run preview          # Build + run with wrangler dev

# Deploy to Cloudflare Workers
cd apps/web && bun run deploy

Adding a New Entity

  1. Schema → packages/shared/src/schemas/product.ts
  2. Table → packages/db/src/schema/products.ts
  3. Repository interface → packages/db/src/repositories/interfaces.ts
  4. Repository implementation → packages/db/src/adapters/d1.ts
  5. Service → packages/db/src/services/product.service.ts
  6. Router → apps/web/src/lib/server/rpc/routers/products.ts
  7. Register → apps/web/src/lib/server/rpc/router.ts
  8. Migrate → bun run db:generate

License

MIT

Top categories

Loading Svelte Themes