Skip to main content
skill CX Codex

convex · mindrally — Claude Code skill: Convex backend guidelines

Tells the agent how to write Convex code: queries, mutations, actions, indexes and file uploads. Useful once Convex is your backend.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add Mindrally/skills --skill convex -a claude-code
Open on GitHub

What convex does

The skill loads a set of Convex conventions into your agent. Convex is a TypeScript backend-as-a-service, and the file covers its four main primitives: query, mutation, action and the HTTP router, plus schemas with indexes, cron jobs and file uploads through ctx.storage.generateUploadUrl().

Code style is spelled out too. Functional declarations, interfaces over types, union types instead of enums, variable names like isLoading and hasError. For the UI layer it points at Shadcn UI, Radix UI and Tailwind CSS, and asks you to keep useClient, useEffect and useState to a minimum. Errors get guard clauses at the top of a function, forms get Zod validation.

Performance has its own section. Filters give way to indexes: declare them in schema.ts with .index(), then call .withIndex() in the query. Large result sets go through .paginate(), single results through .first() instead of .collect(). External APIs belong in actions only — never in queries or mutations. If your codebase already calls fetch inside a query, that is worth a look.

What it helps with

  • define a Convex table schema with indexes on status and user
  • write a mutation that checks auth via ctx.auth.getUserIdentity()
  • move an external API call out of a query into an action
  • set up a cron job that cleans up old records
  • upload a file to Convex storage and save its storageId

Example prompts for the agent

  • add an items table to the Convex schema with by_status and by_user indexes
  • rewrite this query to use .withIndex() instead of .filter()
  • create an action that sends an email through an external API

How to install convex

1Skills CLI (Vercel)

npx skills add Mindrally/skills --skill convex -a claude-code

2Manually: put the files in place

~/.claude/skills/convex/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/convex/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about convex

How do I install the convex skill in Claude?

Run npx skills add Mindrally/skills --skill convex -a claude-code. The skill lands at ~/.claude/skills/convex/SKILL.md.

What does the convex skill do?

It gives the agent Convex development rules: how to write queries, mutations and actions, how to declare a schema with indexes, and how to handle files and cron jobs.

Can a Convex query call an external API?

No. The skill pushes side effects into actions and keeps queries and mutations clean.

Source text

SKILL.md · Apache-2.0
---
name: convex
description: Guidelines for developing with Convex backend-as-a-service platform, covering queries, mutations, actions, and real-time data patterns
metadata:
  maintainer: Mindrally
  source: https://github.com/Mindrally/skills
---

# Convex Development Guidelines

You are an expert in Convex backend development, TypeScript, and real-time data synchronization patterns.

## General Development Specifications

### Code Style and Structure

- Write concise TypeScript using functional declarations, iterators, and modules
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError)
- Structure code with exported components, subcomponents, helpers, and static types
- Use dash-case for directories with named exports
- Prefer interfaces over types; avoid enums in favor of union types
- Use functional components with declarative JSX patterns

### Error Handling

- Handle errors early in functions with guard clauses
- Log errors appropriately for debugging
- Provide user-friendly error messages
- Use Zod for form validation
- Implement proper error boundaries in React components

### UI Framework Integration

- Use Shadcn UI and Radix UI for component primitives
- Style with Tailwind CSS using responsive, mobile-first design
- Minimize useClient, useEffect, and useState usage
- Leverage React Server Components where applicable
- Use Suspense for loading states and dynamic loading for code splitting

## Convex-Specific Patterns

### Queries

Structure queries using the `query` constructor:

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

export const getItems = query({
  args: {
    status: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    // ctx provides: db, storage, auth
    const identity = await ctx.auth.getUserIdentity();

    if (args.status) {
      return await ctx.db
        .query("items")
        .withIndex("by_status", (q) => q.eq("status", args.status))
        .collect();
    }

    return await ctx.db.query("items").collect();
  },
});
```

**Important**: Prefer Convex indexes over filters for better performance. Define indexes in schema.ts using the `.index()` method, then query with `.withIndex()`.

### Mutations

Structure mutations for database writes:

```typescript
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const createItem = mutation({
  args: {
    title: v.string(),
    description: v.optional(v.string()),
  },
  handler: async (ctx, args) => {
    const identity = await ctx.auth.getUserIdentity();
    if (!identity) {
      throw new Error("Not authenticated");
    }

    return await ctx.db.insert("items", {
      title: args.title,
      description: args.description,
      userId: identity.subject,
      createdAt: Date.now(),
    });
  },
});
```

### Actions

Use actions for external API calls and side effects:

```typescript
import { action } from "./_generated/server";
import { v } from "convex/values";

export const sendEmail = action({
  args: {
    to: v.string(),
    subject: v.string(),
    body: v.string(),
  },
  handler: async (ctx, args) => {
    // Actions can call external APIs
    const response = await fetch("https://api.email-service.com/send", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(args),
    });

    return response.ok;
  },
});
```

### Schema Definition with Indexes

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

export default defineSchema({
  items: defineTable({
    title: v.string(),
    description: v.optional(v.string()),
    status: v.string(),
    userId: v.string(),
    createdAt: v.number(),
  })
    .index("by_status", ["status"])
    .index("by_user", ["userId"])
    .index("by_user_and_status", ["userId", "status"]),
});
```

### HTTP Router

Define HTTP routes for webhooks and external integrations:

```typescript
import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";

const http = httpRouter();

http.route({
  path: "/webhook",
  method: "POST",
  handler: httpAction(async (ctx, request) => {
    const body = await request.json();
    // Process webhook
    return new Response(JSON.stringify({ success: true }), {
      status: 200,
      headers: { "Content-Type": "application/json" },
    });
  }),
});

export default http;
```

### Scheduled Jobs

Implement cron jobs for recurring tasks:

```typescript
import { cronJobs } from "convex/server";
import { internal } from "./_generated/api";

const crons = cronJobs();

// Run every hour
crons.interval(
  "cleanup-old-items",
  { hours: 1 },
  internal.tasks.cleanupOldItems
);

// Run at specific time (daily at midnight UTC)
crons.monthly(
  "monthly-report",
  { day: 1, hourUTC: 0, minuteUTC: 0 },
  internal.reports.generateMonthlyReport
);

export default crons;
```

### File Handling

Three-step process for file uploads:

```typescript
// 1. Generate upload URL (mutation)
export const generateUploadUrl = mutation(async (ctx) => {
  return await ctx.storage.generateUploadUrl();
});

// 2. Client POSTs file to the URL
// const uploadUrl = await generateUploadUrl();
// const response = await fetch(uploadUrl, { method: "POST", body: file });
// const { storageId } = await response.json();

// 3. Save storage ID to database (mutation)
export const saveFile = mutation({
  args: {
    storageId: v.id("_storage"),
    filename: v.string(),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert("files", {
      storageId: args.storageId,
      filename: args.filename,
    });
  },
});
```

## Best Practices

1. **Always use indexes** for queries that filter or sort data
2. **Validate arguments** using Convex validators (`v.string()`, `v.number()`, etc.)
3. **Check authentication** early in handlers that require it
4. **Use internal functions** for operations that should not be exposed to clients
5. **Leverage real-time subscriptions** - Convex queries automatically update when data changes
6. **Keep mutations small** and focused on single operations
7. **Use actions for side effects** - never call external APIs from queries or mutations
8. **Handle errors gracefully** with proper error messages for users

## Performance Considerations

- Use `.withIndex()` instead of `.filter()` whenever possible
- Paginate large result sets using `.paginate()`
- Use `.first()` instead of `.collect()` when expecting a single result
- Consider data denormalization for frequently accessed data
- Use Convex's built-in caching - avoid implementing your own

© Mindrally · Apache-2.0 · Mindrally/skills

Similar skills

Everything for Backend and APIs →

convex by other authors comes first.

convex convex Router skill for Convex backend work: it picks the right convex-* procedure for your task and pulls current instructions from a served capability catalog. CX Codex +1 108,000installs convex waynesutton Routes Convex backend tasks to dedicated builder skills and enforces global rules for queries, mutations, and schemas. Useful as the starting point for any Convex project. CX Codex +1 5,700installs convex-expert convex A skill for any code under convex/: functions, schemas, indexes, validators. Useful when your agent writes Convex backend code. CX Codex +1 36,200installs convex-best-practices waynesutton Guides your agent through production Convex patterns, from index design to OCC conflict prevention. Essential for clean mutations, schema validation, and fast queries. CX Codex +1 3,900installs convex-functions waynesutton Writes Convex queries, mutations and actions in the object form, with args and returns validators, correct ctx usage and runtime boundaries. CX Codex +1 3,200installs convex-create-component convex A skill to design and build reusable Convex components with isolated tables and a clear API boundary. Useful when you need to extract backend logic into a self-contained module or package an integration that owns its own data. CX Codex +1 130,900installs appwrite-python appwrite Gives your agent reference code for the Appwrite Python SDK: users, tables, file storage and functions. CX Codex +1 1,100installs replica-backend Jakeschincariol Builds the backend of an app clone: auth, database migrations and access rules, Stripe payments, email and background jobs. Reads replica/architecture.md and keeps a checklist in replica/backend.md. CX Codex +1 613installs

From the same set168

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor