This source did not publish a separate summary. Review SKILL.md before using the skill.
SKILL.md
Convex
You are an expert in Convex — the open-source, reactive backend platform where queries are TypeScript code. You have deep knowledge of schema design, function authoring (queries, mutations, actions), real-time data subscriptions, authentication, file storage, scheduling, and deployment workflows across React, Next.js, Angular, Vue, Svelte, React Native, and server-side environments.
When to Use
Use when building a new project with Convex as the backend
Use when adding Convex to an existing React, Next.js, Angular, Vue, Svelte, or React Native app
Use when designing schemas for a Convex document-relational database
Use when writing or debugging Convex functions (queries, mutations, actions)
Use when implementing real-time/reactive data patterns
Use when setting up authentication with Convex Auth or third-party providers (Clerk, Auth0, etc.)
Use when working with Convex file storage, scheduled functions, or cron jobs
Use when deploying or managing Convex projects
Core Concepts
Convex is a document-relational database with a fully managed backend. Key differentiators:
Reactive by default: Queries automatically re-run and push updates to all connected clients when underlying data changes
TypeScript-first: All backend logic — queries, mutations, actions, schemas — is written in TypeScript
ACID transactions: Serializable isolation with optimistic concurrency control
No infrastructure to manage: Serverless, scales automatically, zero config
End-to-end type safety: Types flow from schema → backend functions → client hooks
Function Types
Type
Purpose
Can Read DB
Can Write DB
Can Call External APIs
Cached/Reactive
Query
Read data
✅
❌
❌
✅
Mutation
Write data
✅
✅
❌
❌
Action
Side effects
via runQuery
via runMutation
✅
❌
HTTP Action
Webhooks/custom endpoints
via runQuery
via runMutation
✅
❌
Project Setup
New Project (Next.js)
npx create-next-app@latest my-app
cd my-app && npm install convex
npx convex dev
Add to Existing Project
npm install convex
npx convex dev
The npx convex dev command:
Prompts you to log in (GitHub)
Creates a project and deployment
Generates convex/ folder for backend functions
Syncs functions to your dev deployment in real-time
Creates .env.local with CONVEX_DEPLOYMENT and NEXT_PUBLIC_CONVEX_URL
Convex provides a robust, native authentication library (@convex-dev/auth) featuring Magic Links, Passwords, and 80+ OAuth providers without needing a third-party service.
// app/ConvexClientProvider.tsx
"use client";
import { ConvexAuthProvider } from "@convex-dev/auth/react";
import { ConvexReactClient } from "convex/react";
import { ReactNode } from "react";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export function ConvexClientProvider({ children }: { children: ReactNode }) {
return (
<ConvexAuthProvider client={convex}>
{children}
</ConvexAuthProvider>
);
}
// Client-side sign in
import { useAuthActions } from "@convex-dev/auth/react";
export function Login() {
const { signIn } = useAuthActions();
return <button onClick={() => signIn("github")}>Sign in with GitHub</button>;
}
With Auth (Third-Party Clerk Example)
If you prefer a hosted third-party solution like Clerk:
// app/ConvexClientProvider.tsx
"use client";
import { ConvexProviderWithClerk } from "convex/react-clerk";
import { ClerkProvider, useAuth } from "@clerk/nextjs";
import { ConvexReactClient } from "convex/react";
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);
export function ConvexClientProvider({ children }: { children: ReactNode }) {
return (
<ClerkProvider publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!}>
<ConvexProviderWithClerk client={convex} useAuth={useAuth}>
{children}
</ConvexProviderWithClerk>
</ClerkProvider>
);
}
With Auth (Better Auth Component)
Convex also has a community component (@convex-dev/better-auth) that integrates the Better Auth library directly into the Convex backend. This is currently in early alpha.
npm install better-auth @convex-dev/better-auth
npx convex env set BETTER_AUTH_SECRET your-secret-here
npx convex env set SITE_URL http://localhost:3000
Better Auth provides email/password, social logins, two-factor authentication, and session management — all running inside Convex functions rather than an external auth server.
Angular Integration
Convex does not have an official Angular client library, but Angular apps can use the core convex package directly with Angular's Dependency Injection and Signals.
// services/convex.service.ts
import { Injectable, signal, effect, OnDestroy } from "@angular/core";
import { ConvexClient } from "convex/browser";
import { api } from "../../convex/_generated/api";
import { FunctionReturnType } from "convex/server";
@Injectable({ providedIn: "root" })
export class ConvexService implements OnDestroy {
private client = new ConvexClient(environment.convexUrl);
// Reactive signal — updates automatically when data changes
tasks = signal<FunctionReturnType<typeof api.tasks.list> | undefined>(
undefined,
);
constructor() {
// Subscribe to a reactive query
this.client.onUpdate(api.tasks.list, {}, (result) => {
this.tasks.set(result);
});
}
async addTask(text: string) {
await this.client.mutation(api.tasks.create, {
text,
isCompleted: false,
});
}
ngOnDestroy() {
this.client.close();
}
}
Note: The community library @robmanganelly/ngx-convex provides a more Angular-native experience with React-like hooks adapted for Angular DI and Signals.
# Set environment variables for your deployment
npx convex env set OPENAI_API_KEY sk-...
npx convex env set SENDGRID_API_KEY SG...
# List current env vars
npx convex env list
# Remove an env var
npx convex env unset OPENAI_API_KEY
Access in actions (NOT in queries or mutations):
// Only available in actions
const apiKey = process.env.OPENAI_API_KEY;
Deployment & CLI
# Development (watches for changes, syncs to dev deployment)
npx convex dev
# Deploy to production
npx convex deploy
# Import data
npx convex import --table tasks data.jsonl
# Export data
npx convex export --path ./backup
# Open Convex dashboard
npx convex dashboard
# Run a function from CLI
npx convex run tasks:list
# View logs
npx convex logs
Best Practices
✅ Define schemas — adds type safety across your entire stack
✅ Use indexes for queries — avoids full table scans
✅ Use compound indexes with equality filters first, range filter last
✅ Rely on native determinism — Date.now() and Math.random() are 100% safe to use in queries and mutations because Convex freezes time at the start of every function execution!
✅ Use v.id("tableName") for document references instead of plain strings
✅ Use actions for external API calls (never call external APIs from queries or mutations)
✅ Use ctx.runQuery / ctx.runMutation from actions — never access ctx.db directly in actions
✅ Add argument validators to all functions — they enforce runtime type safety
✅ Return null when a document isn't found instead of throwing an error unless missing is exceptional
✅ Prefer withIndex over .filter() for query performance
Anti-Patterns to Avoid
❌ External API calls in queries/mutations: Only actions can call external services. Queries and mutations run in the Convex transaction engine.
❌ Doing slow CPU-bound work in mutations: Mutations block database commits; offload heavy processing to actions.
❌ Using .collect() on large tables without limits: Fetches all documents into memory. Use .take(N) or .paginate().
❌ Skipping schema definition: Without a schema you lose end-to-end type safety, the main Convex advantage.
❌ Using .filter() instead of indexes: .filter() does a full table scan. Define an index and use .withIndex().
❌ Storing large blobs in documents: Use Convex file storage (_storage) for files; keep documents lean.
❌ Circular runQuery/runMutation chains: Actions calling mutations that schedule actions can create infinite loops.
Common Pitfalls
Problem: "Query returns undefined on first render"
Solution: This is expected — Convex queries are async. Check for undefined before rendering (this means loading, not empty).
Problem: "Mutation throws Document not found"
Solution: Documents may have been deleted between your read and write due to optimistic concurrency. Re-read inside the mutation.
Problem: "process.env is undefined in query/mutation"
Solution: Environment variables are only accessible in actions (not queries or mutations) because queries/mutations run in the deterministic transaction engine.
Problem: "Function handler is too slow"
Solution: Add indexes for your query patterns. Use withIndex() instead of .filter(). For complex operations, break into smaller mutations.
Problem: "Schema push fails with existing data"
Solution: Convex validates existing data against new schemas. Either migrate existing documents first, or use v.optional() for new fields.