Kirimase vs Create T3 App: CLI-Generated Starters 2026
TL;DR
They're complementary, not competitors — and the community knows it. create-t3-app generates your initial Next.js + tRPC + Prisma project scaffold once. Kirimase adds ongoing code generation: run kirimase generate to scaffold Prisma models, tRPC routers, Zod validators, and UI forms throughout development. Think of create-t3-app as your project initializer and Kirimase as your development accelerator. Many teams use both: T3 to start, Kirimase to maintain velocity.
Key Takeaways
- create-t3-app: ~270K downloads/week, one-time scaffold, the gold standard initial setup
- Kirimase: smaller but growing, ongoing CRUD generation on top of T3 projects
- Kirimase init: supports T3 Stack, Next.js + Drizzle, custom configs
- Kirimase generate: creates Prisma model → tRPC router → Zod schema → UI form in one command
- DX: Both are CLI-based, Kirimase is more opinionated about the generated patterns
- Use together: start with
create-t3-app, add Kirimase later for feature scaffolding
Create T3 App: The Standard Initializer
npm create t3-app@latest
# Interactive prompts:
# ✔ What will your project be called? my-saas
# ✔ Will you be using TypeScript? Yes
# ✔ Will you be using tRPC? Yes
# ✔ What authentication provider would you like to use? NextAuth.js
# ✔ What database ORM would you like to use? Prisma
# ✔ Would you like to use Tailwind CSS? Yes
# ✔ What package manager? pnpm
# ✔ Should we run 'pnpm install' for you? Yes
# ✔ Initialize a new git repository? Yes
What You Get
Generated structure:
my-saas/
├── src/
│ ├── app/
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ └── api/
│ │ ├── auth/[...nextauth]/route.ts
│ │ └── trpc/[trpc]/route.ts
│ ├── server/
│ │ ├── api/
│ │ │ ├── root.ts ← tRPC root router
│ │ │ ├── trpc.ts ← tRPC context setup
│ │ │ └── routers/
│ │ │ └── post.ts ← Example router
│ │ ├── auth.ts ← NextAuth config
│ │ └── db.ts ← Prisma client
│ ├── trpc/
│ │ ├── query-client.ts ← TanStack Query config
│ │ ├── react.tsx ← Client-side hooks
│ │ └── server.ts ← Server-side caller
│ └── styles/globals.css
├── prisma/schema.prisma
├── .env.example
└── next.config.js
T3's generated code is minimal and clean — it gives you the wiring, not the features.
// Generated tRPC router (src/server/api/routers/post.ts):
import { z } from 'zod';
import { createTRPCRouter, protectedProcedure, publicProcedure } from '~/server/api/trpc';
export const postRouter = createTRPCRouter({
hello: publicProcedure
.input(z.object({ text: z.string() }))
.query(({ input }) => ({ greeting: `Hello ${input.text}` })),
create: protectedProcedure
.input(z.object({ name: z.string().min(1) }))
.mutation(async ({ ctx, input }) => {
return ctx.db.post.create({
data: { name: input.name, createdBy: { connect: { id: ctx.session.user.id } } },
});
}),
getLatest: protectedProcedure.query(async ({ ctx }) => {
return ctx.db.post.findFirst({
orderBy: { createdAt: 'desc' },
where: { createdBy: { id: ctx.session.user.id } },
});
}),
});
Kirimase: Ongoing Code Generation
Kirimase wraps the T3 stack and adds kirimase generate — the ability to scaffold new models with full CRUD stack throughout development.
# Install globally:
npm install -g kirimase
# Initialize in an existing Next.js project (or start fresh):
kirimase init
# Prompts: Database? Prisma | ORM? Yes | Auth? NextAuth | Package manager? pnpm
# Add a package with guided configuration:
kirimase add
# Prompts: What to add? (shadcn, stripe, resend, clerk, lucia...)
# Generate full CRUD for a model:
kirimase generate
kirimase generate In Action
kirimase generate
# Prompts:
# ✔ Model name: Project
# ✔ Add field: name | String | required
# ✔ Add field: description | String | optional
# ✔ Add field: status | Enum (active, paused, archived) | default: active
# ✔ Add field: userId | String | foreignKey → User
# ✔ Done adding fields
# ✔ Generate server actions (not tRPC)? No, use tRPC
What gets generated:
// 1. Prisma schema addition (appended to schema.prisma):
model Project {
id String @id @default(cuid())
name String
description String?
status ProjectStatus @default(active)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum ProjectStatus {
active
paused
archived
}
// 2. Zod schema (src/lib/db/schema/projects.ts):
import { z } from 'zod';
export const projectIdSchema = z.object({ id: z.string() });
export type ProjectId = z.infer<typeof projectIdSchema>;
export const insertProjectSchema = z.object({
name: z.string(),
description: z.string().optional(),
status: z.enum(['active', 'paused', 'archived']).default('active'),
});
export type NewProjectParams = z.infer<typeof insertProjectSchema>;
export const updateProjectSchema = insertProjectSchema;
export type UpdateProjectParams = z.infer<typeof updateProjectSchema>;
// 3. tRPC router (src/server/api/routers/projects.ts):
import { createTRPCRouter, protectedProcedure } from '~/server/api/trpc';
import {
projectIdSchema,
insertProjectSchema,
updateProjectSchema,
} from '~/lib/db/schema/projects';
export const projectsRouter = createTRPCRouter({
getProjects: protectedProcedure.query(async ({ ctx }) => {
return ctx.db.project.findMany({ where: { userId: ctx.session.user.id } });
}),
getProjectById: protectedProcedure
.input(projectIdSchema)
.query(async ({ ctx, input }) => {
return ctx.db.project.findFirst({
where: { id: input.id, userId: ctx.session.user.id },
});
}),
createProject: protectedProcedure
.input(insertProjectSchema)
.mutation(async ({ ctx, input }) => {
return ctx.db.project.create({
data: { ...input, userId: ctx.session.user.id },
});
}),
updateProject: protectedProcedure
.input(updateProjectSchema.extend({ id: z.string() }))
.mutation(async ({ ctx, input }) => {
const { id, ...data } = input;
return ctx.db.project.update({ where: { id }, data });
}),
deleteProject: protectedProcedure
.input(projectIdSchema)
.mutation(async ({ ctx, input }) => {
return ctx.db.project.delete({ where: { id: input.id } });
}),
});
// 4. React form component (src/components/projects/ProjectForm.tsx):
'use client';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { api } from '~/trpc/react';
import { insertProjectSchema, type NewProjectParams } from '~/lib/db/schema/projects';
export function ProjectForm({ onSuccess }: { onSuccess?: () => void }) {
const { register, handleSubmit, formState: { errors } } = useForm<NewProjectParams>({
resolver: zodResolver(insertProjectSchema),
});
const createProject = api.projects.createProject.useMutation({
onSuccess: () => {
onSuccess?.();
},
});
return (
<form onSubmit={handleSubmit((data) => createProject.mutate(data))}>
<div>
<label>Name</label>
<input {...register('name')} />
{errors.name && <p>{errors.name.message}</p>}
</div>
<div>
<label>Description</label>
<textarea {...register('description')} />
</div>
<div>
<label>Status</label>
<select {...register('status')}>
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="archived">Archived</option>
</select>
</div>
<button type="submit" disabled={createProject.isPending}>
{createProject.isPending ? 'Creating...' : 'Create Project'}
</button>
</form>
);
}
One kirimase generate command = Prisma model + Zod schemas + tRPC CRUD router + React form.
Comparison
| create-t3-app | Kirimase | |
|---|---|---|
| Purpose | Initial project scaffold | Ongoing feature generation |
| When to use | Project creation | Throughout development |
| Generated output | Full project structure | Per-model CRUD stack |
| Flexibility | High (minimal opinions) | Medium (opinionated patterns) |
| Downloads/week | ~270K | Smaller |
| Auth support | NextAuth | NextAuth, Lucia, Clerk |
| ORM support | Prisma, Drizzle | Prisma, Drizzle |
| Maintenance | T3 OSS team | Community |
Decision Guide
Use create-t3-app if:
→ Starting a new T3-stack project (always use this)
→ Want the community-standard setup
→ Prefer minimal generated code you write yourself
Use Kirimase if:
→ Already have a T3/Next.js project
→ Tired of writing boilerplate CRUD manually
→ Want consistent patterns across all models
→ Building data-heavy apps (lots of models)
Use both (recommended):
1. create-t3-app to initialize
2. Kirimase for each new model/resource
→ Get T3's quality foundation + Kirimase's velocity
Explore T3 Stack, Kirimase, and all CLI-generated starters at StarterPick.