Receber por email
← Voltar para o catálogo

convex

Expert guidance for Convex backend development including queries, mutations, actions, schemas, authentication, scheduling, file storage, search, and Next.js integration. Use when working with Convex functions, database operations, convex/ directory code, or Next.js App Router with Convex. Triggers: convex functions, ctx.db, useQuery, useMutation, usePreloadedQuery, preloadQuery, fetchQuery, convex

17estrelas
Atualizado há 8 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add PolarCoding85/convex-agent-skillz

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/convex-polarcoding85/svg)](https://www.skillteca.com.br/skills/convex-polarcoding85)
#ai

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Convex Backend Development

Core Architecture

Convex is a reactive database where queries are TypeScript functions. The sync engine (queries + mutations + database) is the heart of Convex — center your app around it.

Function Types

| Type | DB Access | Deterministic | Cached/Reactive | Use For | | ------------ | ------------- | ------------- | --------------- | -------------------------- | | query | Read only | Yes | Yes | All reads, subscriptions | | mutation | Read/Write | Yes | No | All writes (transactions) | | action | Via ctx.run\ | No | No | External APIs, LLMs, email | | httpAction | Via ctx.run\ | No | No | Webhooks, custom HTTP |

Key rule: Queries and mutations cannot make network requests. Actions cannot directly access the database.

Project Structure (Best Practice)

convex/
├── _generated/         # Auto-generated types (commit this)
├── schema.ts           # Database schema
├── model/              # Helper functions (most logic lives here)
│   ├── users.ts
│   └── messages.ts
├── users.ts            # Thin wrappers exposing public API
├── messages.ts
├── crons.ts            # Cron job definitions
└── http.ts             # HTTP action routes

Essential Patterns

1. Function Structure

// convex/messages.ts
import { query, mutation, internalMutation } from './_generated/server';
import { internal } from './_generated/api';
import { v } from 'convex/values';

// PUBLIC query with validators (always validate public functions)
export const list = query({
  args: { channelId: v.id('channels') },
  handler: async (ctx, { channelId }) => {
    return await ctx.db
      .query('messages')
      .withIndex('by_channel', (q) => q.eq('channelId', channelId))
      .order('desc')
      .take(50);
  }
});

// PUBLIC mutation with validators and auth check
export const send = mutation({
  args: { channelId: v.id('channels'), body: v.string() },
  handler: async (ctx, { channelId, body }) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) throw new Error('Unauthorized');

    await ctx.db.insert('messages', {
      channelId,
      body,
      authorId: user.subject
    });
  }
});

// INTERNAL mutation (for scheduling, crons, actions)
export const deleteOld = internalMutation({
  args: { before: v.number() },
  handler: async (ctx, { before }) => {
    const old = await ctx.db
      .query('messages')
      .withIndex('by_createdAt', (q) => q.lt('_creationTime', before))
      .take(100);
    for (const msg of old) {
      await ctx.db.delete(msg._id);
    }
  }
});

2. Helper Functions Pattern

Most logic should live in helper functions, NOT in query/mutation handlers:

// convex/model/users.ts
import { QueryCtx, MutationCtx } from '../_generated/server';
import { Doc } from '../_generated/dataModel';

export async function getCurrentUser(
  ctx: QueryCtx
): Promise<Doc<'users'> | null> {
  const identity = await ctx.auth.getUserIdentity();
  if (!identity) return null;

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

export async function requireUser(ctx: QueryCtx): Promise<Doc<'users'>> {
  const user = await getCurrentUser(ctx);
  if (!user) throw new Error('Unauthorized');
  return user;
}

3. Actions with Scheduling

// convex/ai.ts
import { action, internalMutation } from './_generated/server';
import { internal } from './_generated/api';
import { v } from 'convex/values';

export const summarize = action({
  args: { documentId: v.id('documents') },
  handler: async (ctx, { documentId }) => {
    // Read data via internal query
    const doc = await ctx.runQuery(internal.documents.get, { documentId });

    // Call external API
    const response = await fetch('https://api.openai.com/v1/...', {...});
    const summary = await response.json();

    // Write result via internal mutation
    await ctx.runMutation(internal.documents.setSummary, {
      documentId,
      summary: summary.text
    });
  }
});

// Trigger action from mutation (not directly from client)
export const requestSummary = mutation({
  args: { documentId: v.id('documents') },
  handler: async (ctx, { documentId }) => {
    const user = await ctx.auth.getUserIdentity();
    if (!user) throw new Error('Unauthorized');

    await ctx.db.patch(documentId, { status: 'processing' });

    // Schedule action (runs after mutation commits)
    await ctx.scheduler.runAfter(0, internal.ai.summarizeInternal, {
      documentId
    });
  }
});

4. Application Errors

import { ConvexError } from 'convex/values';

export const assignRole = mutation({
  args: { roleId: v.id('roles'), userId: v.id('users') },
  handler: async (ctx, { roleId, userId }) => {
    const existing = await ctx.db
      .query('assignments')
      .withIndex('by_role', (q) => q.eq('roleId', roleId))
      .first();

    if (existing) {
      throw new ConvexError({
        code: 'ROLE_TAKEN',
        message: 'Role is already assigned'
      });
    }

    await ctx.db.insert('assignments', { roleId, userId });
  }
});

Critical Rules

DO ✅

  • Use internal. functions for all ctx.run*, ctx.scheduler, and crons
  • Always validate args for public functions with v.* validators
  • Always check auth in public functions: ctx.auth.getUserIdentity()
  • Use indexes with .withIndex() instead of .filter()
  • Await all promises (enable no-floating-promises ESLint rule)
  • Keep actions small — put logic in queries/mutations
  • Batch database operations in single mutations
  • Use ConvexError for user-facing errors

DON'T ❌

  • Don't use api. functions for scheduling (use internal.)
  • Don't use .filter() on queries — use indexes or TypeScript filter
  • Don't use .collect() on unbounded queries (use .take() or pagination)
  • Don't use Date.now() in queries (breaks caching)
  • Don't call actions directly from client (trigger via mutation + scheduler)
  • Don't make sequential ctx.runQuery/runMutation calls in actions (batch them)
  • Don't use ctx.runAction unless switching runtimes (use helper functions)

Reference Guides

For detailed patterns, see:

  • [FUNCTIONS.md](references/FUNCTIONS.md) — Queries, mutations, actions, internal functions
  • [VALIDATION.md](references/VALIDATION.md) — Argument validation, extended validators
  • [ERROR_HANDLING.md](references/ERROR_HANDLING.md) — ConvexError, application errors
  • [HTTP_ACTIONS.md](references/HTTP_ACTIONS.md) — HTTP actions, CORS, webhooks
  • [RUNTIMES.md](references/RUNTIMES.md) — Default vs Node.js runtime, bundling, debugging
  • [DATABASE.md](references/DATABASE.md) — Schema, indexes, reading/writing data
  • [SEARCH.md](references/SEARCH.md) — Full-text search, vector search, RAG patterns
  • [ADVANCED.md](references/ADVANCED.md) — System tables, schema philosophy, OCC
  • [AUTH.md](references/AUTH.md) — Row-level security, Convex Auth (first-party)
  • [SCHEDULING.md](references/SCHEDULING.md) — Crons, scheduled functions, workflows
  • [FILE_STORAGE.md](references/FILE_STORAGE.md) — Upload, store, serve, delete files
  • [NEXTJS.md](references/NEXTJS.md) — Next.js App Router, SSR, Server Actions

Auth Provider Skills (add to project as needed):

  • convex-auth — Universal auth patterns, storing users, debugging
  • convex-clerk — Clerk setup, webhooks, JWT configuration
  • convex-workos — WorkOS AuthKit setup, auto-provisioning
Compartilhar X LinkedIn