convex-best-practices

Implements Convex function patterns covering validation, indexes, error handling, and write conflicts.

Updated May 28, 2026
One-click install
npx skills add https://github.com/mrisoli/pokerhouse --skill convex-best-practices-mrisoli
Or copy as Structured Prompt for Agent▼
Please help me install this Agent Skill.
Skill: convex-best-practices
Source: https://github.com/mrisoli/pokerhouse/tree/main/.agents/skills/convex-best-practices
Command: npx skills add https://github.com/mrisoli/pokerhouse --skill convex-best-practices-mrisoli

SYSTEM DOCUMENTATION & REQUIREMENTS

💡 This Skill requires @convex-dev/eslint-plugin.

What problem does it solve? Developers building Convex backends often write functions without argument validators, use slow filter-based queries instead of indexes, and create non-idempotent mutations that fail under optimistic concurrency control, leading to runtime errors and performance issues. ## Core Features & Use Cases - Function Organization Patterns: Provides domain-based file structure with public and internal functions using the modern object syntax with handlers. - Validation & Type Safety: Enforces argument and return validators with convex/values, plus proper use of Id and Doc TypeScript types. - Query & Mutation Optimization: Demonstrates index-based queries, idempotent mutations, direct patching, and ConvexError for user-facing errors. - Use Case: When adding a new tasks feature to a Convex app, apply these patterns to define the schema with indexes, write validated CRUD functions, and handle write conflicts correctly. ## Quick Start Review my Convex functions in the backend package and refactor them to follow Convex best practices with validators and indexes.

Frequently Asked Questions about convex-best-practices

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I write Convex functions with argument validation?▼

Define every Convex query and mutation with an args object using validators from convex/values, such as v.string() or v.id("tasks"). Also specify a returns validator so the function's output type is checked and exposed to clients.

How to query Convex data efficiently with indexes?▼

Define indexes in schema.ts using .index() on the table, then query with .withIndex("by_user", q => q.eq(...)) instead of .filter(). Index-based queries avoid full table scans and scale with data size.

What is the @convex-dev/eslint-plugin used for?▼

The @convex-dev/eslint-plugin enforces four Convex rules at build time: modern function syntax, required argument validators, explicit table names in db operations, and no Node imports in the Convex runtime. Install it and extend its recommended config in eslint.config.js.

Why do Convex mutations fail with write conflicts?▼

Convex uses optimistic concurrency control, so mutations conflict when they read and write data modified concurrently. Minimize conflicts by making mutations idempotent, patching documents directly without reading first, and parallelizing independent updates with Promise.all.

When should I use internal functions in Convex?▼

Use internalMutation, internalQuery, or internalAction for logic that must not be callable from clients, such as sensitive updates or scheduled jobs. Internal functions are only invocable from other Convex functions, keeping privileged operations server-side.