Claude Code SkillDevelopment

Convex

"Convex reactive backend expert: schema design, TypeScript functions, real-time subscriptions, auth, file storage, scheduling, and deployment."

Install with the Claude Code Templates CLI
$ npx claude-code-templates@latest --skill="development/convex" --yes

Requires Claude Code. The command adds this skill to your project's .claudedirectory — nothing runs on ToolZip's servers.

What's inside this skill

Component source (preview)

Convex

You are an expert in Convex — the open-source, reactive backend platform where queries are TypeScript code. You have deep knowledge of schema design, function authoring (queries, mutations, actions), real-time data subscriptions, authentication, file storage, scheduling, and deployment workflows across React, Next.js, Angular, Vue, Svelte, React Native, and server-side environments.

When to Use

  • Use when building a new project with Convex as the backend
  • Use when adding Convex to an existing React, Next.js, Angular, Vue, Svelte, or React Native app
  • Use when designing schemas for a Convex document-relational database
  • Use when writing or debugging Convex functions (queries, mutations, actions)
  • Use when implementing real-time/reactive data patterns
  • Use when setting up authentication with Convex Auth or third-party providers (Clerk, Auth0, etc.)
  • Use when working with Convex file storage, scheduled functions, or cron jobs
  • Use when deploying or managing Convex projects

Core Concepts

Convex is a document-relational database with a fully managed backend. Key differentiators:

  • Reactive by default: Queries automatically re-run and push updates to all connected clients when underlying data changes
  • TypeScript-first: All backend logic — queries, mutations, actions, schemas — is written in TypeScript
  • ACID transactions: Serializable isolation with optimistic concurrency control
  • No infrastructure to manage: Serverless, scales automatically, zero config
  • End-to-end type safety: Types flow from schema → backend functions → client hooks

Function Types

TypePurposeCan Read DBCan Write DBCan Call External APIsCached/Reactive
QueryRead data
MutationWrite data
ActionSide effectsvia runQueryvia runMutation
HTTP ActionWebhooks/custom endpointsvia runQueryvia runMutation

Project Setup

New Project (Next.js)

npx create-next-app@latest my-app
cd my-app && npm install convex
npx convex dev

Add to Existing Project

npm install convex
npx convex dev

The npx convex dev command:

  • Prompts you to log in (GitHub)
  • Creates a project and deployment
  • Generates convex/ folder for backend functions
  • Syncs functions to your dev deployment in real-time
  • Creates .env.local with CONVEX_DEPLOYMENT and NEXT_PUBLIC_CONVEX_URL

Folder Structure

my-app/
├── convex/
│   ├── _generated/        ← Auto-generated (DO NOT EDIT)
│   │   ├── api.d.ts
│   │   ├── dataModel.d.ts
│   │   └── server.d.ts
│   ├── schema.ts          ← Database schema definition
│   ├── tasks.ts           ← Query/mutation functions
│   └── http.ts            ← HTTP actions (optional)
├── .env.local             ← CONVEX_DEPLOYMENT, NEXT_PUBLIC_CONVEX_URL
└── convex.json            ← Project config (optional)

Schema Design

Define your schema in convex/schema.ts using the validator library:

import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  users: defineTable({
    name: v.string(),
    email: v.string(),
    avatarUrl: v.optional(v.string()),
    tokenIdentifier: v.string(),
  })
    .index("by_token", ["tokenIdentifier"])
    .index("by_email", ["email"]),

  messages: defineTable({
    authorId: v.id("users"),
    channelId: v.id("channels"),
    body: v.string(),
    attachmentId: v.optional(v.id("_storage")),
  })
    .index("by_channel", ["channelId"])
    .searchIndex("search_body", { searchField: "body" }),

  channels: defineTable({
    name: v.string(),
    description: v.optional(v.string()),
    isPrivate: v.boolean(),
  }),
});

Validator Types

ValidatorTypeScript TypeNotes
v.string()string
v.number()numberIEEE 754 float
v.bigint()bigint
v.boolean()boolean
v.null()null
v.id("tableName")Id<"tableName">Document reference
v.array(v.string())string[]
v.object({...}){...}Nested objects
v.optional(v.string())string \undefined
v.union(v.string(), v.number())string \number
v.literal("active")"active"Literal types
v.bytes()ArrayBufferBinary data
v.float64()numberExplicit 64-bit float (used in vector indexes)
v.any()anyEscape hatch

Indexes

// Single-field index
defineTable({ email: v.string() }).index("by_email", ["email"]);

// Compound index (order matters for range queries)
defineTable({
  orgId: v.string(),
  createdAt: v.number(),
}).index("by_org_and_date", ["orgId", "createdAt"]);

// Full-text search index
defineTable({ body: v.string(), channelId: v.id("channels") }).searchIndex(
  "search_body",
  {
    searchField: "body",
    filterFields: ["channelId"],
  },
);

// Vector search index (for AI/embeddings)
defineTable({ embedding: v.array(v.float64()), text: v.string() }).vectorIndex(
  "by_embedding",
  {
    vectorField: "embedding",
    dimensions: 1536,
  },
);

Writing Functions

Queries (Read Data)

Queries are reactive — clients automatically get updates when data changes.

import { query } from "./_generated/server";
import { v } from "convex/values";

// Simple query — list all tasks
export const list = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("tasks").collect();
  },
});

// Query with arguments and filtering
export const getByChannel = query({
  args: { channelId: v.id("channels") },
  handler: async (ctx, args) => {
    return await ctx.db
      .query("messages")
      .withIndex("by_channel", (q) => q.eq("channelId", args.channelId))
      .order("desc")
      .take(50);
  },
});

// Query with auth check
export const getMyProfile = query({
  args: {},
  handler: async (ctx) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) return null;

    return await ctx.db
      .query("users")
      .withIndex("by_token", (q) =>
        q.eq("tokenIdentifier", identity.tokenIdentifier),
      )
      .unique();
  },
});

### Paginated Queries

Use cursor-based pagination for lists or infinite scroll UIs.
typescript

import { query } from "./_generated/server";

import { paginationOptsValidator } from "convex/server";

export const listPaginated = query({

args: {

paginationOpts: paginationOptsValidator

},

handler: async (ctx, args) => {

return await ctx.db

.query("messages")

.order("desc")

.paginate(args.paginationOpts);

},

});

### Mutations (Write Data)

Mutations run as ACID transactions with serializable isolation.
typescript

import { mutation } from "./_generated/server";

import { v } from "convex/values";

// Insert a document

export const create = mutation({

args: { text: v.string(), isCompleted: v.boolean() },

handler: async (ctx, args) => {

const taskId = await ctx.db.insert("tasks", {

text: args.text,

isCompleted: args.isCompleted,

});

return taskId;

},

});

// Update a document

export const update = mutation({

args: { id: v.id("tasks"), isCompleted: v.boolean() },

handler: async (ctx, args) => {

await ctx.db.patch(args.id, { isCompleted: args.isCompleted });

},

});

// Delete a document

export const remove = mutation({

args: { id: v.id("tasks") },

handler: async (ctx, args) => {

await ctx.db.delete(args.id);

},

});

// Multi-document transaction (automatically atomic)

export const transferCredits = mutation({

args: {

fromUserId: v.id("users"),

toUserId: v.id("users"),

amount: v.number(),

},

handler: async (ctx, args) => {

const fromUser = await ctx.db.get(args.fromUserId);

const toUser = await ctx.db.get(args.toUserId);

if (!fromUser || !toUser) throw new Error("User not found");

if (fromUser.credits < args.amount) throw new Error("Insufficient credits");

await ctx.db.patch(args.fromUserId, {

credits: fromUser.credits - args.amount,

});

await ctx.db.patch(args.toUserId, {

credits: toUser.credits + args.amount,

});

},

});

### Actions (External APIs & Side Effects)

Actions can call third-party services but cannot directly access the database — they must use `ctx.runQuery` and `ctx.runMutation`.
typescript

import { action } from "./_generated/server";

import { v } from "convex/values";

import { api } from "./_generated/api";

export const sendEmail = action({

args: { to: v.string(), subject: v.string(), body: v.string() },

handler: async (ctx, args) => {

// Call external API

const response = await fetch("https://api.sendgrid.com/v3/mail/send", {

method: "POST",

headers: {

Authorization: Bearer ${process.env.SENDGRID_API_KEY},

"Content-Type": "application/json",

},

body: JSON.stringify({

personalizations: [{ to: [{ email: args.to }] }],

from: { email: "noreply@example.com" },

subject: args.subject,

content: [{ type: "text/plain", value: args.body }],

}),

});

if (!response.ok) throw new Error("Failed to send email");

// Write result back to database via mutation

await ctx.runMutation(api.emails.recordSent, {

to: args.to,

subject: args.subject,

sentAt: Date.now(),

});

},

});

// Generate AI embeddings

export const generateEmbedding = action({

args: { text: v.string(), documentId: v.id("documents") },

handler: async (ctx, args) => {

const response = await fetch("https://api.openai.com/v1/embeddings", {

method: "POST",

headers: {

Authorization: Bearer ${process.env.OPENAI_API_KEY},

"Content-Type": "application/json",

},

body: JSON.stringify({

model: "text-embedding-3-small",

input: args.text,

}),

});

const { data } = await response.json();

await ctx.runMutation(api.documents.saveEmbedding, {

documentId: args.documentId,

embedding: data[0].embedding,

});

},

});

### HTTP Actions (Webhooks)
typescript

import { httpRouter } from "convex/server";

import { httpAction } from "./_generated/server";

import { api } from "./_generated/api";

const http = httpRouter();

http.route({

path: "/webhooks/stripe",

method: "POST",

handler: httpAction(async (ctx, request) => {

const body

Preview truncated. View the full source on GitHub →

Type
Skill
Category
Development
Installs
Source
GitHub ↗

Related Claude Code Skills

SkillDevelopment

Code Reviewer

Comprehensive code review skill for TypeScript, JavaScript, Python, Swift, Kotlin, Go. Includes automated code analysis, best practice checking, security scanning, and review checklist generation. Use when reviewing pull requests, providing code feedback, identifying issues, or ensuring code quality standards.

3k installsView →
SkillDevelopment

Senior Frontend

Comprehensive frontend development skill for building modern, performant web applications using ReactJS, NextJS, TypeScript, Tailwind CSS. Includes component scaffolding, performance optimization, bundle analysis, and UI best practices. Use when developing frontend features, optimizing performance, implementing UI/UX designs, managing state, or reviewing frontend code.

2.7k installsView →
SkillDevelopment

Senior Backend

Comprehensive backend development skill for building scalable backend systems using NodeJS, Express, Go, Python, Postgres, GraphQL, REST APIs. Includes API scaffolding, database optimization, security implementation, and performance tuning. Use when designing APIs, optimizing database queries, implementing business logic, handling authentication/authorization, or reviewing backend code.

2.2k installsView →
SkillDevelopment

Senior Architect

Comprehensive software architecture skill for designing scalable, maintainable systems using ReactJS, NextJS, NodeJS, Express, React Native, Swift, Kotlin, Flutter, Postgres, GraphQL, Go, Python. Includes architecture diagram generation, system design patterns, tech stack decision frameworks, and dependency analysis. Use when designing system architecture, making technical decisions, creating architecture diagrams, evaluating trade-offs, or defining integration patterns.

1.9k installsView →
SkillDevelopment

Skill Creator

Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.

1.7k installsView →
SkillDevelopment

Senior Fullstack

Comprehensive fullstack development skill for building complete web applications with React, Next.js, Node.js, GraphQL, and PostgreSQL. Includes project scaffolding, code quality analysis, architecture patterns, and complete tech stack guidance. Use when building new projects, analyzing code quality, implementing design patterns, or setting up development workflows.

1k installsView →

Catalog data and component content are sourced from the open-source davila7/claude-code-templates project (MIT license). ToolZip curates the listing and writes original descriptions; every component links back to its original source. Claude Code is a product of Anthropic. ToolZip is an independent catalog and is not affiliated with or endorsed by Anthropic.