Database
Convex Data Model
How StarterApp organises Convex tables, builders, and generated types.
StarterApp uses Convex for data storage and real-time sync. Schema definitions live in convex/schema.ts and are surfaced through typed helpers in convex/tables.ts.
Tables and Validators
convex/tables.ts exports:
T.*table name constants (e.g.T.user,T.orgMeta,T.rateLimits)V.*validator helpers for IDs (e.g.V.userId,V.orgMetaId)- Type aliases (
UserId,OrgMetaId, etc.)
Avoid hard-coding table strings or Id<"table"> in your code—import from ./tables instead:
import { T, V, type UserId } from "./tables";
export const getOrgMeta = query({
args: { metaId: V.orgMetaId },
handler: async (ctx, { metaId }) => {
const record = await ctx.db.get(metaId);
return record;
},
});
Builders
Custom builders in convex/_helpers/builders.ts inject authentication, Autumn helpers, and user-scoped database proxies. Use userQuery, userMutation, or userAction instead of the raw query/mutation/action APIs for user-facing operations.
import { userMutation } from "./_helpers/builders";
export const updateProfile = userMutation({
args: { name: v.string() },
handler: async (ctx, { name }) => {
await ctx.db.patch(ctx.viewerId as UserId, {
name,
updatedAt: Date.now(),
});
},
});
Codegen
After editing schema.ts, run pnpm codegen to regenerate _generated/*. These files are committed to the repository so CI and AI agents have the latest types.