# Convex Eslint

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

- Skill: `majiayu000/convex-eslint` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/convex-eslint`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/convex-eslint/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/convex-eslint

---


# 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

- https://docs.convex.dev/eslint
- https://www.npmjs.com/package/@convex-dev/eslint-plugin

## 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

- [ESLint Plugin Docs](https://docs.convex.dev/eslint)
- [Explicit IDs Announcement](https://news.convex.dev/db-table-name/)

