Agent skill

convex-eslint

Write Convex code that passes @convex-dev/eslint-plugin rules by default

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/convex-eslint

SKILL.md

Convex ESLint Compliance

Write all Convex functions to pass @convex-dev/eslint-plugin. These rules prevent common bugs, security issues, and ensure code quality.

Documentation Sources

Setup

Install the plugin:

bash
npm i @convex-dev/eslint-plugin --save-dev

Configure eslint.config.js:

javascript
import { defineConfig } from "eslint/config";
import convexPlugin from "@convex-dev/eslint-plugin";

export default defineConfig([...convexPlugin.configs.recommended]);

Rules

1. no-old-registered-function-syntax

Always use object syntax with a handler property.

typescript
// Correct
export const list = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("messages").collect();
  },
});

// Wrong - bare function syntax
export const list = query(async (ctx) => {
  return await ctx.db.query("messages").collect();
});

2. require-argument-validators

Always include args object, even when empty.

typescript
// Correct - with arguments
export const get = query({
  args: { id: v.id("messages") },
  handler: async (ctx, { id }) => {
    return await ctx.db.get("messages", id);
  },
});

// Correct - no arguments
export const listAll = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("messages").collect();
  },
});

// Wrong - missing args
export const get = query({
  handler: async (ctx, { id }: { id: Id<"messages"> }) => {
    return await ctx.db.get("messages", id);
  },
});

3. explicit-table-ids

Use explicit table names in all database operations (Convex 1.31.0+).

typescript
// Correct
const message = await ctx.db.get("messages", messageId);
await ctx.db.patch("messages", messageId, { text: "updated" });
await ctx.db.replace("messages", messageId, {
  text: "replaced",
  author: "Alice",
});
await ctx.db.delete("messages", messageId);

// Wrong - implicit table from ID type
const message = await ctx.db.get(messageId);
await ctx.db.patch(messageId, { text: "updated" });
await ctx.db.replace(messageId, { text: "replaced", author: "Alice" });
await ctx.db.delete(messageId);

Migration codemod available:

bash
npx @convex-dev/codemod@latest explicit-ids

4. import-wrong-runtime

Never import Node.js runtime files into Convex runtime files.

typescript
// convex/queries.ts (no "use node" directive)

// Correct - importing from Convex runtime file
import { helper } from "./utils"; // utils.ts has no "use node"

// Wrong - importing from Node runtime file
import { nodeHelper } from "./nodeUtils"; // nodeUtils.ts has "use node"

Best Practices

  1. Run ESLint before committing: npx eslint convex/
  2. Use auto-fix for quick migrations: npx eslint convex/ --fix
  3. Add to CI pipeline to catch violations early
  4. Configure your editor for real-time feedback

Quick Reference

Rule What it enforces
no-old-registered-function-syntax Object syntax with handler
require-argument-validators args: {} on all functions
explicit-table-ids Table name in db operations
import-wrong-runtime No Node imports in Convex runtime

References

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results