Claude-skill-registry create-schema
Create Zod schemas for new entities/resources in the backend. Use when adding a new resource, creating data models, defining DTOs (CreateType, UpdateType), or setting up validation schemas. Triggers on "new schema", "add entity", "create model", "define type".
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/create-schema" ~/.claude/skills/majiayu000-claude-skill-registry-create-schema && rm -rf "$T"
manifest:
skills/data/create-schema/SKILL.mdsource content
Create Schema
Creates Zod schemas with TypeScript type inference for new entities in this backend template.
Quick Reference
Location:
src/schemas/{entity-name}.schema.ts
Naming: Singular, kebab-case (e.g., note.schema.ts, course-registration.schema.ts)
Instructions
Step 1: Create the Schema File
Create a new file at
src/schemas/{entity-name}.schema.ts
Step 2: Define the Entity ID Schema
Always start with a dedicated ID schema:
import { z } from "zod"; export const {entity}IdSchema = z.string(); export type {Entity}IdType = z.infer<typeof {entity}IdSchema>;
Step 3: Define the Base Entity Schema
export const {entity}Schema = z.object({ id: {entity}IdSchema, // Primary key // ... entity-specific fields ... createdBy: userIdSchema, // If entity is user-owned (import from user.schemas) createdAt: z.date().optional(), // Set by DB/service updatedAt: z.date().optional(), // Set by DB/service }); export type {Entity}Type = z.infer<typeof {entity}Schema>;
Step 4: Define Create DTO Schema
Omit system-managed fields and add validation:
export const create{Entity}Schema = {entity}Schema .omit({ id: true, // Generated by service/system createdBy: true, // Set from authenticated user context createdAt: true, // Set by service/database updatedAt: true, // Set by service/database }) .extend({ // Add stricter validation for required fields fieldName: z.string().min(1, "{Entity} field is required for creation."), }); export type Create{Entity}Type = z.infer<typeof create{Entity}Schema>;
Step 5: Define Update DTO Schema
Make all mutable fields optional:
export const update{Entity}Schema = {entity}Schema .omit({ id: true, // Part of URL, not body createdBy: true, // Immutable createdAt: true, // Immutable updatedAt: true, // Set by service/database }) .partial(); // All fields optional for updates export type Update{Entity}Type = z.infer<typeof update{Entity}Schema>;
Step 6: Define Query Parameters Schema (if needed)
Extend the base query params for filtering:
import { queryParamsSchema } from "./shared.schema"; export const {entity}QueryParamsSchema = queryParamsSchema.extend({ // Entity-specific filters createdBy: userIdSchema.optional(), status: z.enum(["active", "inactive"]).optional(), }); export type {Entity}QueryParamsType = z.infer<typeof {entity}QueryParamsSchema>;
Patterns & Rules
Naming Conventions
- File name:
(singular, kebab-case){entity-name}.schema.ts - Schema variables:
,{entity}Schema
(camelCase)create{Entity}Schema - Type names:
,{Entity}Type
(PascalCase)Create{Entity}Type
Import Rules
- Always use path aliases:
import { x } from "@/schemas/..." - Import shared schemas from
./shared.schema - Import user-related schemas from
when needed./user.schemas
Schema Design Rules
- Always export both schema and type for each definition
- ID schemas are separate - allows reuse and type narrowing
- Timestamps are optional on the base schema (not present on creation)
- Create schemas omit system-managed fields (id, createdBy, timestamps)
- Update schemas are partial - all fields optional
- Extend base queryParamsSchema for entity-specific filters
Validation Guidelines
- Add
for required string fields in create schemas.min(1) - Use
for truly optional fields.optional() - Use
for numeric query params (they come as strings)z.coerce.number() - Add descriptive error messages:
z.string().min(1, "Field is required")
Cross-Reference Pattern
When referencing other entities:
import { userIdSchema } from "./user.schemas"; import { otherEntityIdSchema } from "./other-entity.schema"; export const myEntitySchema = z.object({ id: myEntityIdSchema, ownerId: userIdSchema, // Reference to user relatedId: otherEntityIdSchema, // Reference to another entity });
Complete Example
See
src/schemas/note.schema.ts for a complete reference implementation.
import { z } from "zod"; import { queryParamsSchema } from "./shared.schema"; import { userIdSchema } from "./user.schemas"; // ID Schema export const noteIdSchema = z.string(); export type NoteIdType = z.infer<typeof noteIdSchema>; // Base Entity Schema export const noteSchema = z.object({ id: noteIdSchema, content: z.string(), createdBy: userIdSchema, createdAt: z.date().optional(), updatedAt: z.date().optional(), }); export type NoteType = z.infer<typeof noteSchema>; // Create DTO export const createNoteSchema = noteSchema .omit({ id: true, createdBy: true, createdAt: true, updatedAt: true, }) .extend({ content: z.string().min(1, "Note content is required for creation."), }); export type CreateNoteType = z.infer<typeof createNoteSchema>; // Update DTO export const updateNoteSchema = noteSchema .omit({ id: true, createdBy: true, createdAt: true, updatedAt: true, }) .partial(); export type UpdateNoteType = z.infer<typeof updateNoteSchema>; // Query Parameters export const noteQueryParamsSchema = queryParamsSchema.extend({ createdBy: userIdSchema.optional(), }); export type NoteQueryParamsType = z.infer<typeof noteQueryParamsSchema>;
Shared Schemas Reference
The following are available from
@/schemas/shared.schema:
- Base pagination/sorting params (search, sortBy, sortOrder, page, limit)queryParamsSchema
- Generic paginated response wrapperpaginatedResultsSchema(dataSchema)
- URL path parameter validationentityIdParamSchema(paramName)
,DEFAULT_PAGE
- Pagination defaultsDEFAULT_LIMIT
What NOT to Do
- Do NOT use
- environment config belongs inprocess.envsrc/env.ts - Do NOT create barrel exports (index.ts) - use explicit imports
- Do NOT use plural names (
) - use singular (notes.schema.ts
)note.schema.ts - Do NOT define business logic in schemas - schemas are for structure/validation only
- Do NOT skip type exports - always export both schema and inferred type