Codapult
PricingPluginsDocs
Codapult

The SaaS Boilerplate for Builders

Product

  • Pricing
  • Plugins
  • Documentation

Company

  • Contact
  • GitHub

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Codapult. All rights reserved.

All articles

Getting Started

  • Introduction
  • Quick Start
  • Project Structure

Configuration

  • Environment Variables
  • App Configuration

Authentication

  • Authentication
  • OAuth Providers
  • Two-Factor & Passwordless
  • Enterprise SSO (SAML)

Database

  • Database
  • Migrations

Teams

  • Teams & Organizations
  • Permissions & RBAC

Payments

  • Payments & Billing
  • Stripe Setup
  • LemonSqueezy Setup
  • Polar Setup
  • Payment Webhooks

Api

  • API Layer
  • tRPC
  • GraphQL

Ai

  • AI Features

Email

  • Email
  • Email Templates

Infrastructure

  • Infrastructure
  • File Storage
  • Background Jobs

Ui

  • UI & Theming

I18n

  • Internationalization

Content Management

  • Content Management

Admin

  • Admin Panel

Security

  • Security

Monitoring

  • Analytics & Monitoring

Modules

  • Module Architecture

Plugins

  • Plugin System
  • AI Kit Plugin
  • CRM Plugin
  • Helpdesk Plugin
  • Email Marketing Plugin

Deployment

  • Deployment
  • Troubleshooting

Upgrading

  • Upgrading Codapult

Developer Tools

  • MCP Server
  • Testing
Api

tRPC

Type-safe API procedures with tRPC v11, TanStack React Query, and server-side prefetching.

Codapult includes a full tRPC v11 setup with TanStack React Query and superjson serialization. tRPC provides end-to-end type safety — your client code knows the exact shape of every request and response without code generation.

File Structure

PathDescription
src/lib/trpc/init.tsRouter factory, procedure levels (publicProcedure, protectedProcedure, adminProcedure)
src/lib/trpc/routers/Domain routers — user.ts, billing.ts, notifications.ts
src/lib/trpc/server.tsServer-side caller and prefetch() helper
src/lib/trpc/client.tsClient-side hooks (useTRPC, TRPCProvider, HydrateClient)
src/app/api/trpc/[trpc]/route.tsHTTP endpoint at /api/trpc

Procedure Levels

LevelAuth RequiredUse Case
publicProcedureNoPublic data (plans, features)
protectedProcedureYesUser-scoped data (profile, settings)
adminProcedureYes + admin roleAdmin operations (user management)

Creating a Router

import { z } from 'zod';
import { router, protectedProcedure } from '../init';
import { db } from '@/lib/db';
import { user } from '@/lib/db/schema';
import { eq } from 'drizzle-orm';

export const userRouter = router({
  me: protectedProcedure.query(async ({ ctx }) => {
    const rows = await db
      .select({ id: user.id, name: user.name, email: user.email })
      .from(user)
      .where(eq(user.id, ctx.session.user.id))
      .limit(1);
    return rows[0] ?? null;
  }),

  updateProfile: protectedProcedure
    .input(z.object({ name: z.string().min(1).max(100) }))
    .mutation(async ({ ctx, input }) => {
      await db
        .update(user)
        .set({ name: input.name, updatedAt: new Date() })
        .where(eq(user.id, ctx.session.user.id));
      return { success: true };
    }),
});

To register a new router, add it to the appRouter in src/lib/trpc/router.ts.

Server-Side Prefetch

Use prefetch() in server components to load data before the page renders, then hydrate the cache on the client:

import { prefetch } from '@/lib/trpc/server';
import { HydrateClient } from '@/lib/trpc/client';

export default async function ProfilePage() {
  await prefetch((t) => t.user.me.prefetch());

  return (
    <HydrateClient>
      <ProfileClient />
    </HydrateClient>
  );
}

Client-Side Usage

'use client';

import { useTRPC } from '@/lib/trpc/client';
import { useQuery, useMutation } from '@tanstack/react-query';

export function ProfileClient() {
  const trpc = useTRPC();
  const { data: user } = useQuery(trpc.user.me.queryOptions());

  const updateMutation = useMutation(trpc.user.updateProfile.mutationOptions());

  return (
    <div>
      <h1>Hello, {user?.name}</h1>
      <button onClick={() => updateMutation.mutate({ name: 'New Name' })}>Update</button>
    </div>
  );
}

Adding a New Router

  1. Create a file in src/lib/trpc/routers/ (e.g. projects.ts)
  2. Define queries and mutations using the appropriate procedure level
  3. Register the router in src/lib/trpc/router.ts
  4. Use it on the client via trpc.projects.yourProcedure

The types flow automatically — no code generation or manual type imports needed.

API LayerGraphQL