{"id":"a3067258-1637-4761-bece-01c7fca42c68","shortId":"mFsbKW","kind":"skill","title":"convex","tagline":"Convex reactive backend expert: schema design, TypeScript functions, real-time subscriptions, auth, file storage, scheduling, and deployment.","description":"# Convex\n\nYou 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.\n\n## When to Use\n- Use when building a new project with Convex as the backend\n- Use when adding Convex to an existing React, Next.js, Angular, Vue, Svelte, or React Native app\n- Use when designing schemas for a Convex document-relational database\n- Use when writing or debugging Convex functions (queries, mutations, actions)\n- Use when implementing real-time/reactive data patterns\n- Use when setting up authentication with Convex Auth or third-party providers (Clerk, Auth0, etc.)\n- Use when working with Convex file storage, scheduled functions, or cron jobs\n- Use when deploying or managing Convex projects\n\n## Core Concepts\n\nConvex is a **document-relational** database with a fully managed backend. Key differentiators:\n\n- **Reactive by default**: Queries automatically re-run and push updates to all connected clients when underlying data changes\n- **TypeScript-first**: All backend logic — queries, mutations, actions, schemas — is written in TypeScript\n- **ACID transactions**: Serializable isolation with optimistic concurrency control\n- **No infrastructure to manage**: Serverless, scales automatically, zero config\n- **End-to-end type safety**: Types flow from schema → backend functions → client hooks\n\n### Function Types\n\n| Type            | Purpose                   | Can Read DB    | Can Write DB      | Can Call External APIs | Cached/Reactive |\n| :-------------- | :------------------------ | :------------- | :---------------- | :--------------------- | :-------------- |\n| **Query**       | Read data                 | ✅             | ❌                | ❌                     | ✅              |\n| **Mutation**    | Write data                | ✅             | ✅                | ❌                     | ❌              |\n| **Action**      | Side effects              | via `runQuery` | via `runMutation` | ✅                     | ❌              |\n| **HTTP Action** | Webhooks/custom endpoints | via `runQuery` | via `runMutation` | ✅                     | ❌              |\n\n## Project Setup\n\n### New Project (Next.js)\n\n```bash\nnpx create-next-app@latest my-app\ncd my-app && npm install convex\nnpx convex dev\n```\n\n### Add to Existing Project\n\n```bash\nnpm install convex\nnpx convex dev\n```\n\nThe `npx convex dev` command:\n\n1. Prompts you to log in (GitHub)\n2. Creates a project and deployment\n3. Generates `convex/` folder for backend functions\n4. Syncs functions to your dev deployment in real-time\n5. Creates `.env.local` with `CONVEX_DEPLOYMENT` and `NEXT_PUBLIC_CONVEX_URL`\n\n### Folder Structure\n\n```\nmy-app/\n├── convex/\n│   ├── _generated/        ← Auto-generated (DO NOT EDIT)\n│   │   ├── api.d.ts\n│   │   ├── dataModel.d.ts\n│   │   └── server.d.ts\n│   ├── schema.ts          ← Database schema definition\n│   ├── tasks.ts           ← Query/mutation functions\n│   └── http.ts            ← HTTP actions (optional)\n├── .env.local             ← CONVEX_DEPLOYMENT, NEXT_PUBLIC_CONVEX_URL\n└── convex.json            ← Project config (optional)\n```\n\n## Schema Design\n\nDefine your schema in `convex/schema.ts` using the validator library:\n\n```typescript\nimport { defineSchema, defineTable } from \"convex/server\";\nimport { v } from \"convex/values\";\n\nexport default defineSchema({\n  users: defineTable({\n    name: v.string(),\n    email: v.string(),\n    avatarUrl: v.optional(v.string()),\n    tokenIdentifier: v.string(),\n  })\n    .index(\"by_token\", [\"tokenIdentifier\"])\n    .index(\"by_email\", [\"email\"]),\n\n  messages: defineTable({\n    authorId: v.id(\"users\"),\n    channelId: v.id(\"channels\"),\n    body: v.string(),\n    attachmentId: v.optional(v.id(\"_storage\")),\n  })\n    .index(\"by_channel\", [\"channelId\"])\n    .searchIndex(\"search_body\", { searchField: \"body\" }),\n\n  channels: defineTable({\n    name: v.string(),\n    description: v.optional(v.string()),\n    isPrivate: v.boolean(),\n  }),\n});\n```\n\n### Validator Types\n\n| Validator                         | TypeScript Type       | Notes                                          |\n| :-------------------------------- | :-------------------- | :--------------------------------------------- |\n| `v.string()`                      | `string`              |                                                |\n| `v.number()`                      | `number`              | IEEE 754 float                                 |\n| `v.bigint()`                      | `bigint`              |                                                |\n| `v.boolean()`                     | `boolean`             |                                                |\n| `v.null()`                        | `null`                |                                                |\n| `v.id(\"tableName\")`               | `Id<\"tableName\">`     | Document reference                             |\n| `v.array(v.string())`             | `string[]`            |                                                |\n| `v.object({...})`                 | `{...}`               | Nested objects                                 |\n| `v.optional(v.string())`          | `string \\| undefined` |                                                |\n| `v.union(v.string(), v.number())` | `string \\| number`    |                                                |\n| `v.literal(\"active\")`             | `\"active\"`            | Literal types                                  |\n| `v.bytes()`                       | `ArrayBuffer`         | Binary data                                    |\n| `v.float64()`                     | `number`              | Explicit 64-bit float (used in vector indexes) |\n| `v.any()`                         | `any`                 | Escape hatch                                   |\n\n### Indexes\n\n```typescript\n// Single-field index\ndefineTable({ email: v.string() }).index(\"by_email\", [\"email\"]);\n\n// Compound index (order matters for range queries)\ndefineTable({\n  orgId: v.string(),\n  createdAt: v.number(),\n}).index(\"by_org_and_date\", [\"orgId\", \"createdAt\"]);\n\n// Full-text search index\ndefineTable({ body: v.string(), channelId: v.id(\"channels\") }).searchIndex(\n  \"search_body\",\n  {\n    searchField: \"body\",\n    filterFields: [\"channelId\"],\n  },\n);\n\n// Vector search index (for AI/embeddings)\ndefineTable({ embedding: v.array(v.float64()), text: v.string() }).vectorIndex(\n  \"by_embedding\",\n  {\n    vectorField: \"embedding\",\n    dimensions: 1536,\n  },\n);\n```\n\n## Writing Functions\n\n### Queries (Read Data)\n\nQueries are reactive — clients automatically get updates when data changes.\n\n````typescript\nimport { query } from \"./_generated/server\";\nimport { v } from \"convex/values\";\n\n// Simple query — list all tasks\nexport const list = query({\n  args: {},\n  handler: async (ctx) => {\n    return await ctx.db.query(\"tasks\").collect();\n  },\n});\n\n// Query with arguments and filtering\nexport const getByChannel = query({\n  args: { channelId: v.id(\"channels\") },\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"messages\")\n      .withIndex(\"by_channel\", (q) => q.eq(\"channelId\", args.channelId))\n      .order(\"desc\")\n      .take(50);\n  },\n});\n\n// Query with auth check\nexport const getMyProfile = query({\n  args: {},\n  handler: async (ctx) => {\n    const identity = await ctx.auth.getUserIdentity();\n    if (!identity) return null;\n\n    return await ctx.db\n      .query(\"users\")\n      .withIndex(\"by_token\", (q) =>\n        q.eq(\"tokenIdentifier\", identity.tokenIdentifier),\n      )\n      .unique();\n  },\n});\n\n### Paginated Queries\n\nUse cursor-based pagination for lists or infinite scroll UIs.\n\n```typescript\nimport { query } from \"./_generated/server\";\nimport { paginationOptsValidator } from \"convex/server\";\n\nexport const listPaginated = query({\n  args: {\n    paginationOpts: paginationOptsValidator\n  },\n  handler: async (ctx, args) => {\n    return await ctx.db\n      .query(\"messages\")\n      .order(\"desc\")\n      .paginate(args.paginationOpts);\n  },\n});\n```\n\n### Mutations (Write Data)\n\nMutations run as ACID transactions with serializable isolation.\n\n```typescript\nimport { mutation } from \"./_generated/server\";\nimport { v } from \"convex/values\";\n\n// Insert a document\nexport const create = mutation({\n  args: { text: v.string(), isCompleted: v.boolean() },\n  handler: async (ctx, args) => {\n    const taskId = await ctx.db.insert(\"tasks\", {\n      text: args.text,\n      isCompleted: args.isCompleted,\n    });\n    return taskId;\n  },\n});\n\n// Update a document\nexport const update = mutation({\n  args: { id: v.id(\"tasks\"), isCompleted: v.boolean() },\n  handler: async (ctx, args) => {\n    await ctx.db.patch(args.id, { isCompleted: args.isCompleted });\n  },\n});\n\n// Delete a document\nexport const remove = mutation({\n  args: { id: v.id(\"tasks\") },\n  handler: async (ctx, args) => {\n    await ctx.db.delete(args.id);\n  },\n});\n\n// Multi-document transaction (automatically atomic)\nexport const transferCredits = mutation({\n  args: {\n    fromUserId: v.id(\"users\"),\n    toUserId: v.id(\"users\"),\n    amount: v.number(),\n  },\n  handler: async (ctx, args) => {\n    const fromUser = await ctx.db.get(args.fromUserId);\n    const toUser = await ctx.db.get(args.toUserId);\n    if (!fromUser || !toUser) throw new Error(\"User not found\");\n    if (fromUser.credits < args.amount) throw new Error(\"Insufficient credits\");\n\n    await ctx.db.patch(args.fromUserId, {\n      credits: fromUser.credits - args.amount,\n    });\n    await ctx.db.patch(args.toUserId, {\n      credits: toUser.credits + args.amount,\n    });\n  },\n});\n````\n\n### Actions (External APIs & Side Effects)\n\nActions can call third-party services but cannot directly access the database — they must use `ctx.runQuery` and `ctx.runMutation`.\n\n```typescript\nimport { action } from \"./_generated/server\";\nimport { v } from \"convex/values\";\nimport { api } from \"./_generated/api\";\n\nexport const sendEmail = action({\n  args: { to: v.string(), subject: v.string(), body: v.string() },\n  handler: async (ctx, args) => {\n    // Call external API\n    const response = await fetch(\"https://api.sendgrid.com/v3/mail/send\", {\n      method: \"POST\",\n      headers: {\n        Authorization: `Bearer ${process.env.SENDGRID_API_KEY}`,\n        \"Content-Type\": \"application/json\",\n      },\n      body: JSON.stringify({\n        personalizations: [{ to: [{ email: args.to }] }],\n        from: { email: \"noreply@example.com\" },\n        subject: args.subject,\n        content: [{ type: \"text/plain\", value: args.body }],\n      }),\n    });\n\n    if (!response.ok) throw new Error(\"Failed to send email\");\n\n    // Write result back to database via mutation\n    await ctx.runMutation(api.emails.recordSent, {\n      to: args.to,\n      subject: args.subject,\n      sentAt: Date.now(),\n    });\n  },\n});\n\n// Generate AI embeddings\nexport const generateEmbedding = action({\n  args: { text: v.string(), documentId: v.id(\"documents\") },\n  handler: async (ctx, args) => {\n    const response = await fetch(\"https://api.openai.com/v1/embeddings\", {\n      method: \"POST\",\n      headers: {\n        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,\n        \"Content-Type\": \"application/json\",\n      },\n      body: JSON.stringify({\n        model: \"text-embedding-3-small\",\n        input: args.text,\n      }),\n    });\n\n    const { data } = await response.json();\n    await ctx.runMutation(api.documents.saveEmbedding, {\n      documentId: args.documentId,\n      embedding: data[0].embedding,\n    });\n  },\n});\n```\n\n### HTTP Actions (Webhooks)\n\n```typescript\nimport { httpRouter } from \"convex/server\";\nimport { httpAction } from \"./_generated/server\";\nimport { api } from \"./_generated/api\";\n\nconst http = httpRouter();\n\nhttp.route({\n  path: \"/webhooks/stripe\",\n  method: \"POST\",\n  handler: httpAction(async (ctx, request) => {\n    const body = await request.text();\n    const signature = request.headers.get(\"stripe-signature\");\n\n    // Verify webhook signature here...\n\n    const event = JSON.parse(body);\n    await ctx.runMutation(api.payments.handleWebhook, { event });\n\n    return new Response(\"OK\", { status: 200 });\n  }),\n});\n\nexport default http;\n```\n\n## Client-Side Integration\n\n### React / Next.js\n\n```typescript\n// app/ConvexClientProvider.tsx\n\"use client\";\nimport { ConvexProvider, ConvexReactClient } from \"convex/react\";\nimport { ReactNode } from \"react\";\n\nconst convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);\n\nexport function ConvexClientProvider({ children }: { children: ReactNode }) {\n  return <ConvexProvider client={convex}>{children}</ConvexProvider>;\n}\n```\n\n```typescript\n// app/layout.tsx — wrap children\nimport { ConvexClientProvider } from \"./ConvexClientProvider\";\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html lang=\"en\">\n      <body>\n        <ConvexClientProvider>{children}</ConvexClientProvider>\n      </body>\n    </html>\n  );\n}\n```\n\n```typescript\n// Component using Convex hooks\n\"use client\";\nimport { useQuery, useMutation } from \"convex/react\";\nimport { api } from \"@/convex/_generated/api\";\n\nexport function TaskList() {\n  // Reactive query — auto-updates when data changes\n  const tasks = useQuery(api.tasks.list);\n  const addTask = useMutation(api.tasks.create);\n  const toggleTask = useMutation(api.tasks.update);\n\n  if (tasks === undefined) return <p>Loading...</p>;\n\n  return (\n    <div>\n      {tasks.map((task) => (\n        <div key={task._id}>\n          <input\n            type=\"checkbox\"\n            checked={task.isCompleted}\n            onChange={() =>\n              toggleTask({ id: task._id, isCompleted: !task.isCompleted })\n            }\n          />\n          {task.text}\n        </div>\n      ))}\n      <button onClick={() => addTask({ text: \"New task\", isCompleted: false })}>\n        Add Task\n      </button>\n    </div>\n  );\n}\n```\n\n```typescript\n// Component using Paginated Queries\n\"use client\";\nimport { usePaginatedQuery } from \"convex/react\";\nimport { api } from \"@/convex/_generated/api\";\n\nexport function MessageLog() {\n  const { results, status, loadMore } = usePaginatedQuery(\n    api.messages.listPaginated,\n    {}, // args\n    { initialNumItems: 20 }\n  );\n\n  return (\n    <div>\n      {results.map((msg) => (\n        <div key={msg._id}>{msg.body}</div>\n      ))}\n\n      {status === \"LoadingFirstPage\" && <p>Loading...</p>}\n\n      {status === \"CanLoadMore\" && (\n        <button onClick={() => loadMore(20)}>Load More</button>\n      )}\n    </div>\n  );\n}\n```\n\n### With Auth (First-Party Convex Auth)\n\nConvex provides a robust, native authentication library (`@convex-dev/auth`) featuring Magic Links, Passwords, and 80+ OAuth providers without needing a third-party service.\n\n```typescript\n// app/ConvexClientProvider.tsx\n\"use client\";\nimport { ConvexAuthProvider } from \"@convex-dev/auth/react\";\nimport { ConvexReactClient } from \"convex/react\";\nimport { ReactNode } from \"react\";\n\nconst convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);\n\nexport function ConvexClientProvider({ children }: { children: ReactNode }) {\n  return (\n    <ConvexAuthProvider client={convex}>\n      {children}\n    </ConvexAuthProvider>\n  );\n}\n```\n\n```typescript\n// Client-side sign in\nimport { useAuthActions } from \"@convex-dev/auth/react\";\n\nexport function Login() {\n  const { signIn } = useAuthActions();\n  return <button onClick={() => signIn(\"github\")}>Sign in with GitHub</button>;\n}\n```\n\n### With Auth (Third-Party Clerk Example)\n\nIf you prefer a hosted third-party solution like Clerk:\n\n```typescript\n// app/ConvexClientProvider.tsx\n\"use client\";\nimport { ConvexProviderWithClerk } from \"convex/react-clerk\";\nimport { ClerkProvider, useAuth } from \"@clerk/nextjs\";\nimport { ConvexReactClient } from \"convex/react\";\n\nconst convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);\n\nexport function ConvexClientProvider({ children }: { children: ReactNode }) {\n  return (\n    <ClerkProvider publishableKey={process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY!}>\n      <ConvexProviderWithClerk client={convex} useAuth={useAuth}>\n        {children}\n      </ConvexProviderWithClerk>\n    </ClerkProvider>\n  );\n}\n```\n\n### With Auth (Better Auth Component)\n\nConvex 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**.\n\n```bash\nnpm install better-auth @convex-dev/better-auth\nnpx convex env set BETTER_AUTH_SECRET your-secret-here\nnpx convex env set SITE_URL http://localhost:3000\n```\n\nBetter Auth provides email/password, social logins, two-factor authentication, and session management — all running inside Convex functions rather than an external auth server.\n\n### Angular Integration\n\nConvex 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.\n\n```typescript\n// services/convex.service.ts\nimport { Injectable, signal, effect, OnDestroy } from \"@angular/core\";\nimport { ConvexClient } from \"convex/browser\";\nimport { api } from \"../../convex/_generated/api\";\nimport { FunctionReturnType } from \"convex/server\";\n\n@Injectable({ providedIn: \"root\" })\nexport class ConvexService implements OnDestroy {\n  private client = new ConvexClient(environment.convexUrl);\n\n  // Reactive signal — updates automatically when data changes\n  tasks = signal<FunctionReturnType<typeof api.tasks.list> | undefined>(\n    undefined,\n  );\n\n  constructor() {\n    // Subscribe to a reactive query\n    this.client.onUpdate(api.tasks.list, {}, (result) => {\n      this.tasks.set(result);\n    });\n  }\n\n  async addTask(text: string) {\n    await this.client.mutation(api.tasks.create, {\n      text,\n      isCompleted: false,\n    });\n  }\n\n  ngOnDestroy() {\n    this.client.close();\n  }\n}\n```\n\n```typescript\n// Component usage\nimport { Component, inject } from \"@angular/core\";\nimport { ConvexService } from \"./services/convex.service\";\n\n@Component({\n  selector: \"app-task-list\",\n  template: `\n    @if (convex.tasks(); as tasks) {\n      @for (task of tasks; track task._id) {\n        <div>{{ task.text }}</div>\n      }\n    } @else {\n      <p>Loading...</p>\n    }\n    <button (click)=\"convex.addTask('New task')\">Add Task</button>\n  `,\n})\nexport class TaskListComponent {\n  convex = inject(ConvexService);\n}\n```\n\n> **Note:** The community library `@robmanganelly/ngx-convex` provides a more Angular-native experience with React-like hooks adapted for Angular DI and Signals.\n\n## Scheduling & Cron Jobs\n\n### One-off Scheduled Functions\n\n```typescript\nimport { mutation } from \"./_generated/server\";\nimport { api } from \"./_generated/api\";\n\nexport const sendReminder = mutation({\n  args: { userId: v.id(\"users\"), message: v.string(), delayMs: v.number() },\n  handler: async (ctx, args) => {\n    await ctx.scheduler.runAfter(args.delayMs, api.notifications.send, {\n      userId: args.userId,\n      message: args.message,\n    });\n  },\n});\n```\n\n### Cron Jobs\n\n```typescript\n// convex/crons.ts\nimport { cronJobs } from \"convex/server\";\nimport { api } from \"./_generated/api\";\n\nconst crons = cronJobs();\n\ncrons.interval(\"clear old logs\", { hours: 24 }, api.logs.clearOld);\n\ncrons.cron(\n  \"weekly digest\",\n  \"0 9 * * 1\", // Every Monday at 9 AM\n  api.emails.sendWeeklyDigest,\n);\n\nexport default crons;\n```\n\n## File Storage\n\n```typescript\n// Generate an upload URL (mutation)\nexport const generateUploadUrl = mutation({\n  args: {},\n  handler: async (ctx) => {\n    return await ctx.storage.generateUploadUrl();\n  },\n});\n\n// Save file reference after upload (mutation)\nexport const saveFile = mutation({\n  args: { storageId: v.id(\"_storage\"), name: v.string() },\n  handler: async (ctx, args) => {\n    await ctx.db.insert(\"files\", {\n      storageId: args.storageId,\n      name: args.name,\n    });\n  },\n});\n\n// Get a URL to serve a file (query)\nexport const getFileUrl = query({\n  args: { storageId: v.id(\"_storage\") },\n  handler: async (ctx, args) => {\n    return await ctx.storage.getUrl(args.storageId);\n  },\n});\n```\n\n## Environment Variables\n\n```bash\n# Set environment variables for your deployment\nnpx convex env set OPENAI_API_KEY sk-...\nnpx convex env set SENDGRID_API_KEY SG...\n\n# List current env vars\nnpx convex env list\n\n# Remove an env var\nnpx convex env unset OPENAI_API_KEY\n```\n\nAccess in actions (NOT in queries or mutations):\n\n```typescript\n// Only available in actions\nconst apiKey = process.env.OPENAI_API_KEY;\n```\n\n## Deployment & CLI\n\n```bash\n# Development (watches for changes, syncs to dev deployment)\nnpx convex dev\n\n# Deploy to production\nnpx convex deploy\n\n# Import data\nnpx convex import --table tasks data.jsonl\n\n# Export data\nnpx convex export --path ./backup\n\n# Open Convex dashboard\nnpx convex dashboard\n\n# Run a function from CLI\nnpx convex run tasks:list\n\n# View logs\nnpx convex logs\n```\n\n## Best Practices\n\n- ✅ Define schemas — adds type safety across your entire stack\n- ✅ Use indexes for queries — avoids full table scans\n- ✅ Use compound indexes with equality filters first, range filter last\n- ✅ 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!\n- ✅ Use `v.id(\"tableName\")` for document references instead of plain strings\n- ✅ Use actions for external API calls (never call external APIs from queries or mutations)\n- ✅ Use `ctx.runQuery` / `ctx.runMutation` from actions — never access `ctx.db` directly in actions\n- ✅ Add argument validators to all functions — they enforce runtime type safety\n- ✅ Return `null` when a document isn't found instead of throwing an error unless missing is exceptional\n- ✅ Prefer `withIndex` over `.filter()` for query performance\n\n## Anti-Patterns to Avoid\n\n1. **❌ External API calls in queries/mutations**: Only actions can call external services. Queries and mutations run in the Convex transaction engine.\n2. **❌ Doing slow CPU-bound work in mutations**: Mutations block database commits; offload heavy processing to actions.\n3. **❌ Using `.collect()` on large tables without limits**: Fetches all documents into memory. Use `.take(N)` or `.paginate()`.\n4. **❌ Skipping schema definition**: Without a schema you lose end-to-end type safety, the main Convex advantage.\n5. **❌ Using `.filter()` instead of indexes**: `.filter()` does a full table scan. Define an index and use `.withIndex()`.\n6. **❌ Storing large blobs in documents**: Use Convex file storage (`_storage`) for files; keep documents lean.\n7. **❌ Circular `runQuery`/`runMutation` chains**: Actions calling mutations that schedule actions can create infinite loops.\n\n## Common Pitfalls\n\n- **Problem:** \"Query returns `undefined` on first render\"\n  **Solution:** This is expected — Convex queries are async. Check for `undefined` before rendering (this means loading, not empty).\n\n- **Problem:** \"Mutation throws `Document not found`\"\n  **Solution:** Documents may have been deleted between your read and write due to optimistic concurrency. Re-read inside the mutation.\n\n- **Problem:** \"`process.env` is undefined in query/mutation\"\n  **Solution:** Environment variables are only accessible in **actions** (not queries or mutations) because queries/mutations run in the deterministic transaction engine.\n\n- **Problem:** \"Function handler is too slow\"\n  **Solution:** Add indexes for your query patterns. Use `withIndex()` instead of `.filter()`. For complex operations, break into smaller mutations.\n\n- **Problem:** \"Schema push fails with existing data\"\n  **Solution:** Convex validates existing data against new schemas. Either migrate existing documents first, or use `v.optional()` for new fields.\n\n## Limitations\n\n- Queries and mutations cannot call external HTTP APIs (use actions instead)\n- No raw SQL — you work with the Convex query builder API\n- Environment variables only available in actions, not in queries or mutations\n- Document size limit of 1MB\n- Maximum function execution time limits apply\n- No server-side rendering of Convex data without specific SSR patterns (use preloading)\n- Schemas are enforced at write-time; changing schemas requires data migration for existing documents\n\n## Related Skills\n\n- `@firebase` — Alternative BaaS with Firestore (compare: Convex is TypeScript-first with ACID transactions)\n- `@supabase-automation` — Alternative with PostgreSQL backend (compare: Convex is document-relational with built-in reactivity)\n- `@prisma-expert` — ORM for traditional databases (Convex replaces both ORM and database)\n- `@react-patterns` — Frontend patterns that pair well with Convex React hooks\n- `@nextjs-app-router` — Next.js App Router integration patterns\n- `@authentication-oauth` — Auth patterns (Convex supports Clerk, Auth0, Convex Auth)\n- `@stripe` — Payment integration via Convex actions and HTTP webhooks\n\n## Resources\n\n- [Official Docs](https://docs.convex.dev)\n- [Convex Stack (Blog)](https://stack.convex.dev)\n- [GitHub](https://github.com/get-convex/convex-backend)\n- [Discord Community](https://convex.dev/community)\n- [Convex Chef (AI Starter)](https://chef.convex.dev)","tags":["convex","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity-skills"],"capabilities":["skill","source-sickn33","skill-convex","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/convex","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34831 github stars · SKILL.md body (25,258 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-24T06:50:58.307Z","embedding":null,"createdAt":"2026-04-18T21:35:14.697Z","updatedAt":"2026-04-24T06:50:58.307Z","lastSeenAt":"2026-04-24T06:50:58.307Z","tsv":"'/../convex/_generated/api':1610 '/_generated/api':949,1102,1747,1783 '/_generated/server':633,739,779,941,1098,1743 '/auth':1336 '/auth/react':1362,1402 '/backup':1975 '/better-auth':1495,1522 '/community)':2562 '/convex/_generated/api':1217,1288 '/convexclientprovider':1192 '/get-convex/convex-backend)':2557 '/reactive':133 '/services/convex.service':1674 '/v1/embeddings':1051 '/v3/mail/send':974 '/webhooks/stripe':1108 '0':1085,1797 '1':328,1799,2128 '100':2034 '1536':613 '1mb':2422 '2':335,2149 '20':1300,1316 '200':1143 '24':1792 '3':341,1070,2167 '3000':1541 '4':348,2185 '5':359,2204 '50':688 '6':2222 '64':535 '7':2238 '754':494 '80':1342 '9':1798,1803 'access':928,1923,2083,2318 'acid':220,770,2472 'across':63,2004 'action':50,126,214,272,280,395,913,918,939,953,1034,1088,1925,1935,2064,2081,2087,2135,2166,2243,2248,2320,2394,2412,2542 'activ':524,525 'ad':92 'adapt':1725 'add':312,1272,1700,2001,2088,2340 'addtask':1234,1266,1652 'advantag':2203 'ai':1029,2565 'ai/embeddings':600 'alpha':1512 'also':1487 'altern':2461,2477 'amount':868 'angular':66,99,1566,1574,1578,1588,1717,1727 'angular-n':1716 'angular/core':1602,1670 'anti':2124 'anti-pattern':2123 'api':264,915,947,967,981,1058,1100,1215,1286,1608,1745,1781,1893,1901,1921,1939,2067,2072,2130,2392,2406 'api.d.ts':383 'api.documents.saveembedding':1080 'api.emails.recordsent':1021 'api.emails.sendweeklydigest':1805 'api.logs.clearold':1793 'api.messages.listpaginated':1297 'api.notifications.send':1767 'api.openai.com':1050 'api.openai.com/v1/embeddings':1049 'api.payments.handlewebhook':1136 'api.sendgrid.com':973 'api.sendgrid.com/v3/mail/send':972 'api.tasks.create':1236,1657 'api.tasks.list':1232,1647 'api.tasks.update':1240 'apikey':1937 'app':105,297,301,305,374,1579,1678,2519,2522 'app-task-list':1677 'app/convexclientprovider.tsx':1154,1353,1437 'app/layout.tsx':1186 'appli':2428 'application/json':986,1063 'arg':647,665,672,697,748,754,791,799,818,827,840,847,861,873,954,964,1035,1044,1298,1752,1763,1821,1838,1847,1867,1874 'args.amount':895,906,912 'args.body':1002 'args.channelid':684 'args.delayms':1766 'args.documentid':1082 'args.fromuserid':878,903 'args.id':830,850 'args.iscompleted':808,832 'args.message':1771 'args.name':1854 'args.paginationopts':763 'args.storageid':1852,1878 'args.subject':997,1025 'args.text':806,1073 'args.to':992,1023 'args.touserid':883,909 'args.userid':1769 'argument':658,2089 'arraybuff':529 'async':649,670,699,752,797,825,845,871,962,1042,1113,1651,1761,1823,1845,1872,2269 'atom':856 'attachmentid':461 'auth':14,143,691,1320,1325,1419,1482,1484,1500,1518,1528,1543,1564,2529,2536 'auth0':150,2534 'authent':56,140,1331,1551,2527 'authentication-oauth':2526 'author':47,978,1055 'authorid':453 'auto':378,1224 'auto-gener':377 'auto-upd':1223 'autom':2476 'automat':191,234,623,855,1631 'avail':1933,2410 'avatarurl':438 'avoid':2012,2127 'await':652,674,703,710,756,802,828,848,876,881,901,907,970,1019,1047,1076,1078,1118,1134,1655,1764,1826,1848,1876 'baa':2462 'back':1014 'backend':4,32,89,184,210,247,346,1506,2480 'base':727 'bash':292,316,1513,1881,1943 'bearer':979,1056 'best':1997 'better':1483,1499,1517,1527,1542 'better-auth':1516 'bigint':497 'binari':530 'bit':536 'blob':2225 'block':2159 'blog':2552 'bodi':459,471,473,584,591,593,959,987,1064,1117,1133 'boolean':499 'bound':2154 'break':2354 'build':81 'builder':2405 'built':2489 'built-in':2488 'button':1264,1313,1410,1695 'cached/reactive':265 'call':262,920,965,2068,2070,2131,2137,2244,2389 'canloadmor':1312 'cannot':926,2388 'cd':302 'chain':2242 'chang':205,628,1228,1634,1947,2450 'channel':458,467,474,588,668,680 'channelid':456,468,586,595,666,683 'check':692,1255,2270 'checkbox':1254 'chef':2564 'chef.convex.dev':2567 'children':1177,1178,1184,1188,1197,1198,1201,1382,1383,1389,1464,1465,1480 'circular':2239 'class':1619,1703 'clear':1788 'clerk':149,1423,1435,1472,2533 'clerk/nextjs':1448 'clerkprovid':1445,1468 'cli':1942,1986 'click':1696 'client':201,249,622,1148,1156,1182,1208,1280,1355,1387,1392,1439,1476,1575,1624 'client-sid':1147,1391 'code':38 'collect':655,2169 'command':327 'commit':2161 'common':2253 'communiti':1490,1710,2559 'compar':2465,2481 'complex':2352 'compon':1203,1275,1485,1491,1664,1667,1675 'compound':559,2017 'concept':172 'concurr':226,2300 'config':236,406 'connect':200 'const':644,662,694,701,745,788,800,815,837,858,874,879,951,968,1032,1045,1074,1103,1116,1120,1130,1166,1229,1233,1237,1292,1371,1406,1453,1749,1784,1818,1835,1864,1936 'constructor':1640 'content':984,998,1061 'content-typ':983,1060 'control':227 'convex':1,2,20,26,86,93,112,122,142,156,169,173,308,310,319,321,325,343,363,368,375,398,402,1167,1172,1183,1205,1324,1326,1334,1360,1372,1377,1388,1400,1454,1459,1477,1486,1493,1505,1520,1524,1535,1558,1568,1584,1705,1889,1897,1909,1917,1953,1959,1964,1972,1977,1980,1988,1995,2043,2146,2202,2229,2266,2366,2403,2435,2466,2482,2499,2514,2531,2535,2541,2550,2563 'convex-dev':1333,1359,1399,1492,1519 'convex.addtask':1697 'convex.dev':2561 'convex.dev/community)':2560 'convex.json':404 'convex.tasks':1683 'convex/browser':1606 'convex/crons.ts':1775 'convex/react':1161,1213,1284,1366,1452 'convex/react-clerk':1443 'convex/schema.ts':414 'convex/server':424,743,1094,1614,1779 'convex/values':428,637,783,945 'convexauthprovid':1357,1386 'convexcli':1604,1626 'convexclientprovid':1176,1190,1381,1463 'convexprovid':1158,1181 'convexproviderwithclerk':1441,1475 'convexreactcli':1159,1169,1364,1374,1450,1456 'convexservic':1620,1672,1707 'core':171,1583 'cpu':2153 'cpu-bound':2152 'creat':295,336,360,789,2250 'create-next-app':294 'createdat':569,577 'credit':900,904,910 'cron':162,1732,1772,1785,1808 'cronjob':1777,1786 'crons.cron':1794 'crons.interval':1787 'ctx':650,671,700,753,798,826,846,872,963,1043,1114,1762,1824,1846,1873 'ctx.auth.getuseridentity':704 'ctx.db':675,711,757,2084 'ctx.db.delete':849 'ctx.db.get':877,882 'ctx.db.insert':803,1849 'ctx.db.patch':829,902,908 'ctx.db.query':653 'ctx.runmutation':936,1020,1079,1135,2079 'ctx.runquery':934,2078 'ctx.scheduler.runafter':1765 'ctx.storage.generateuploadurl':1827 'ctx.storage.geturl':1877 'current':1509,1905 'cursor':726 'cursor-bas':725 'dashboard':1978,1981 'data':54,134,204,268,271,531,618,627,766,1075,1084,1227,1633,1962,1970,2364,2369,2436,2453 'data.jsonl':1968 'databas':116,179,387,930,1016,2160,2498,2504 'datamodel.d.ts':384 'date':575 'date.now':1027,2030 'db':257,260 'debug':121 'deep':41 'default':189,430,1145,1194,1807 'defin':410,1999,2216 'defineschema':421,431 'definet':422,433,452,475,552,566,583,601 'definit':389,2188 'delaym':1758 'delet':833,2291 'depend':1590 'deploy':19,61,166,340,354,364,399,1887,1941,1951,1955,1960 'desc':686,761 'descript':478 'design':7,45,108,409 'determin':2029 'determinist':2330 'dev':311,322,326,353,1335,1361,1401,1494,1521,1950,1954 'develop':1944 'di':1728 'differenti':186 'digest':1796 'dimens':612 'direct':927,1502,1586,2085 'discord':2558 'div':1249,1304 'doc':2548 'docs.convex.dev':2549 'document':114,177,506,786,813,835,853,1040,2057,2103,2177,2227,2236,2283,2287,2376,2418,2457,2485 'document-rel':113,176,2484 'documentid':1038,1081 'due':2297 'earli':1511 'edit':382 'effect':274,917,1599 'either':2373 'els':1693 'email':436,449,450,553,557,558,991,994,1011 'email/password':1545 'embed':602,609,611,1030,1069,1083,1086 'empti':2279 'end':238,240,2195,2197 'end-to-end':237,2194 'endpoint':282 'enforc':2095,2445 'engin':2148,2332 'entir':2006 'env':1525,1536,1890,1898,1906,1910,1914,1918 'env.local':361,397 'environ':75,1879,1883,2314,2407 'environment.convexurl':1627 'equal':2020 'error':889,898,1007,2111 'escap':544 'etc':151 'event':1131,1137 'everi':1800,2050 'exampl':1424 'except':2115 'execut':2052,2425 'exist':96,314,2363,2368,2375,2456 'expect':2265 'experi':1719 'expert':5,24,2494 'explicit':534 'export':429,643,661,693,744,787,814,836,857,950,1031,1144,1174,1193,1218,1289,1379,1403,1461,1618,1702,1748,1806,1817,1834,1863,1969,1973 'extern':263,914,966,1563,2066,2071,2129,2138,2390 'factor':1550 'fail':1008,2361 'fals':1271,1660 'featur':1337 'fetch':971,1048,2175 'field':550,2383 'file':15,57,157,1809,1829,1850,1861,2230,2234 'filter':660,2021,2024,2119,2206,2210,2350 'filterfield':594 'firebas':2460 'firestor':2464 'first':208,1322,2022,2260,2377,2470 'first-parti':1321 'float':495,537 'flow':244 'folder':344,370 'found':892,2106,2285 'freez':2044 'fromus':875,885 'fromuser.credits':894,905 'fromuserid':862 'frontend':2508 'full':579,2013,2213 'full-text':578 'fulli':182 'function':9,46,123,160,248,251,347,350,392,615,1175,1195,1219,1290,1380,1404,1462,1559,1738,1984,2051,2093,2334,2424 'functionreturntyp':1612,1637 'generat':342,376,379,1028,1812 'generateembed':1033 'generateuploadurl':1819 'get':624,1855 'getbychannel':663 'getfileurl':1865 'getmyprofil':695 'github':334,1413,1417,2554 'github.com':2556 'github.com/get-convex/convex-backend)':2555 'handler':648,669,698,751,796,824,844,870,961,1041,1111,1760,1822,1844,1871,2335 'hatch':545 'header':977,1054 'heavi':2163 'hook':250,1206,1724,2516 'host':1429 'hour':1791 'http':279,394,1087,1104,1146,2391,2544 'http.route':1106 'http.ts':393 'httpaction':1096,1112 'httprouter':1092,1105 'id':504,819,841,1259 'ident':702,706 'identity.tokenidentifier':720 'ieee':493 'implement':129,1621 'import':420,425,630,634,736,740,776,780,938,942,946,1091,1095,1099,1157,1162,1189,1209,1214,1281,1285,1356,1363,1367,1396,1440,1444,1449,1596,1603,1607,1611,1666,1671,1740,1744,1776,1780,1961,1965 'index':443,447,465,541,546,551,555,560,571,582,598,2009,2018,2209,2218,2341 'infinit':732,2251 'infrastructur':229 'initialnumitem':1299 'inject':1591,1597,1615,1668,1706 'input':1072,1252 'insert':784 'insid':1557,2304 'instal':307,318,1515 'instead':2059,2107,2207,2348,2395 'insuffici':899 'integr':1150,1497,1567,2524,2539 'iscomplet':794,807,822,831,1261,1270,1659 'isn':2104 'isol':223,774 'ispriv':481 'job':163,1733,1773 'json.parse':1132 'json.stringify':988,1065 'keep':2235 'key':185,982,1059,1250,1305,1474,1894,1902,1922,1940 'knowledg':42 'larg':2171,2224 'last':2025 'latest':298 'lean':2237 'librari':418,1332,1501,1576,1711 'like':1434,1723 'limit':2174,2384,2420,2427 'link':1339 'list':640,645,730,1680,1904,1911,1991 'listpagin':746 'liter':526 'load':1245,1310,1317,1694,2277 'loadingfirstpag':1309 'loadmor':1295,1315 'localhost':1540 'log':332,1790,1993,1996 'logic':211 'login':1405,1547 'loop':2252 'lose':2193 'magic':1338 'main':2201 'manag':168,183,231,1554 'math.random':2032 'matter':562 'maximum':2423 'may':2288 'mean':2276 'memori':2179 'messag':451,677,759,1756,1770 'messagelog':1291 'method':975,1052,1109 'migrat':2374,2454 'miss':2113 'model':1066 'monday':1801 'msg':1303 'msg._id':1306 'msg.body':1307 'multi':852 'multi-docu':851 'must':932 'mutat':49,125,213,269,764,767,777,790,817,839,860,1018,1741,1751,1816,1820,1833,1837,1930,2041,2076,2142,2157,2158,2245,2281,2306,2324,2357,2387,2417 'my-app':299,303,372 'n':2182 'name':434,476,1842,1853 'nativ':70,104,1330,1718,2028 'need':1346 'nest':512 'never':2069,2082 'new':83,289,888,897,1006,1139,1168,1268,1373,1455,1625,1698,2371,2382 'next':296,366,400 'next.js':65,98,291,1152,2521 'nextj':2518 'nextjs-app-rout':2517 'ngondestroy':1661 'noreply@example.com':995 'note':488,1708 'npm':306,317,1514 'npx':293,309,320,324,1523,1534,1888,1896,1908,1916,1952,1958,1963,1971,1979,1987,1994 'null':501,708,2100 'number':492,522,533 'oauth':1343,2528 'object':513 'offici':1573,2547 'offload':2162 'ok':1141 'old':1789 'onchang':1257 'onclick':1265,1314,1411 'ondestroy':1600,1622 'one':1735 'one-off':1734 'open':29,1976 'open-sourc':28 'openai':1892,1920 'oper':2353 'optimist':225,2299 'option':396,407 'order':561,685,760 'org':573 'orgid':567,576 'orm':2495,2502 'packag':1585 'pagin':722,728,762,1277,2184 'paginationopt':749 'paginationoptsvalid':741,750 'pair':2511 'parti':147,923,1323,1350,1422,1432 'password':1340 'path':1107,1974 'pattern':135,2125,2345,2440,2507,2509,2525,2530 'payment':2538 'perform':2122 'person':989 'pitfal':2254 'plain':2061 'platform':33 'post':976,1053,1110 'postgresql':2479 'practic':1998 'prefer':1427,2116 'preload':2442 'prisma':2493 'prisma-expert':2492 'privat':1623 'problem':2255,2280,2307,2333,2358 'process':2164 'process.env':2308 'process.env.next':1170,1375,1457,1470 'process.env.openai':1057,1938 'process.env.sendgrid':980 'product':1957 'project':84,170,287,290,315,338,405 'prompt':329 'provid':148,1327,1344,1544,1713 'providedin':1616 'public':367,401,1171,1376,1458,1471 'publish':1473 'publishablekey':1469 'purpos':254 'push':196,2360 'q':681,717 'q.eq':682,718 'queri':35,48,124,190,212,266,565,616,619,631,639,646,656,664,676,689,696,712,723,737,747,758,1222,1278,1645,1862,1866,1928,2011,2039,2074,2121,2140,2256,2267,2322,2344,2385,2404,2415 'queries/mutations':2133,2326 'query/mutation':391,2312 'rang':564,2023 'rather':1560 'raw':2397 're':193,2302 're-read':2301 're-run':192 'react':64,69,97,103,1151,1165,1370,1722,2506,2515 'react-lik':1721 'react-pattern':2505 'react.reactnode':1199 'reactiv':3,31,187,621,1221,1628,1644,2491 'reactnod':1163,1179,1368,1384,1466 'read':256,267,617,2294,2303 'real':11,52,131,357 'real-tim':10,51,130,356 'refer':507,1830,2058 'relat':115,178,2458,2486 'reli':2026 'remov':838,1912 'render':2261,2274,2433 'replac':2500 'request':1115 'request.headers.get':1122 'request.text':1119 'requir':2452 'resourc':2546 'respons':969,1046,1140 'response.json':1077 'response.ok':1004 'result':1013,1293,1648,1650 'results.map':1302 'return':651,673,707,709,755,809,1138,1180,1200,1244,1246,1301,1385,1409,1467,1825,1875,2099,2257 'robmanganelly/ngx-convex':1712 'robust':1329 'root':1617 'rootlayout':1196 'router':2520,2523 'run':194,768,1556,1982,1989,2143,2327 'runmut':278,286,2241 'runqueri':276,284,2240 'runtim':2096 'safe':2035 'safeti':242,2003,2098,2199 'save':1828 'savefil':1836 'scale':233 'scan':2015,2215 'schedul':17,59,159,1731,1737,2247 'schema':6,44,109,215,246,388,408,412,2000,2187,2191,2359,2372,2443,2451 'schema.ts':386 'scroll':733 'search':470,581,590,597 'searchfield':472,592 'searchindex':469,589 'secret':1529,1532 'selector':1676 'send':1010 'sendemail':952 'sendgrid':1900 'sendremind':1750 'sentat':1026 'serializ':222,773 'serv':1859 'server':73,1565,2431 'server-sid':72,2430 'server.d.ts':385 'serverless':232 'servic':924,1351,2139 'services/convex.service.ts':1595 'session':1553 'set':138,1526,1537,1882,1891,1899 'setup':288 'sg':1903 'side':74,273,916,1149,1393,2432 'sign':1394,1414 'signal':1593,1598,1629,1636,1730 'signatur':1121,1125,1128 'signin':1407,1412 'simpl':638 'singl':549 'single-field':548 'site':1538 'size':2419 'sk':1895 'skill':2459 'skill-convex' 'skip':2186 'slow':2151,2338 'small':1071 'smaller':2356 'social':1546 'solut':1433,2262,2286,2313,2339,2365 'sourc':30 'source-sickn33' 'specif':2438 'sql':2398 'ssr':2439 'stack':2007,2551 'stack.convex.dev':2553 'start':2048 'starter':2566 'status':1142,1294,1308,1311 'storag':16,58,158,464,1810,1841,1870,2231,2232 'storageid':1839,1851,1868 'store':2223 'string':490,510,516,521,1654,2062 'stripe':1124,2537 'stripe-signatur':1123 'structur':371 'subject':957,996,1024 'subscrib':1641 'subscript':13,55 'supabas':2475 'supabase-autom':2474 'support':2532 'svelt':68,101 'sync':349,1948 'tabl':1966,2014,2172,2214 'tablenam':503,505,2055 'take':687,2181 'task':642,654,804,821,843,1230,1242,1248,1269,1273,1635,1679,1685,1687,1689,1699,1701,1967,1990 'task._id':1251,1260,1691 'task.iscompleted':1256,1262 'task.text':1263,1692 'taskid':801,810 'tasklist':1220 'tasklistcompon':1704 'tasks.map':1247 'tasks.ts':390 'templat':1681 'text':580,605,792,805,1036,1068,1267,1653,1658 'text-embed':1067 'text/plain':1000 'third':146,922,1349,1421,1431 'third-parti':145,921,1348,1420,1430 'this.client.close':1662 'this.client.mutation':1656 'this.client.onupdate':1646 'this.tasks.set':1649 'throw':887,896,1005,2109,2282 'time':12,53,132,358,2045,2426,2449 'toggletask':1238,1258 'token':445,716 'tokenidentifi':441,446,719 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'touser':880,886 'touser.credits':911 'touserid':865 'track':1690 'tradit':2497 'transact':221,771,854,2147,2331,2473 'transfercredit':859 'two':1549 'two-factor':1548 'type':241,243,252,253,484,487,527,985,999,1062,1253,2002,2097,2198 'typescript':8,37,207,219,419,486,547,629,735,775,937,1090,1153,1185,1202,1274,1352,1390,1436,1594,1663,1739,1774,1811,1931,2469 'typescript-first':206,2468 'ui':734 'undefin':517,1243,1638,1639,2258,2272,2310 'under':203 'uniqu':721 'unless':2112 'unset':1919 'updat':197,625,811,816,1225,1630 'upload':1814,1832 'url':369,403,1173,1378,1460,1539,1815,1857 'usag':1665 'use':78,79,90,106,117,127,136,152,164,415,538,724,933,1155,1204,1207,1276,1279,1354,1438,1581,2008,2016,2037,2053,2063,2077,2168,2180,2205,2220,2228,2346,2379,2393,2441 'useauth':1446,1478,1479 'useauthact':1397,1408 'usemut':1211,1235,1239 'usepaginatedqueri':1282,1296 'usequeri':1210,1231 'user':432,455,713,864,867,890,1755 'userid':1753,1768 'v':426,635,781,943 'v.any':542 'v.array':508,603 'v.bigint':496 'v.boolean':482,498,795,823 'v.bytes':528 'v.float64':532,604 'v.id':454,457,463,502,587,667,820,842,863,866,1039,1754,1840,1869,2054 'v.literal':523 'v.null':500 'v.number':491,520,570,869,1759 'v.object':511 'v.optional':439,462,479,514,2380 'v.string':435,437,440,442,460,477,480,489,509,515,519,554,568,585,606,793,956,958,960,1037,1757,1843 'v.union':518 'valid':417,483,485,2090,2367 'valu':1001 'var':1907,1915 'variabl':1880,1884,2315,2408 'vector':540,596 'vectorfield':610 'vectorindex':607 'verifi':1126 'via':275,277,283,285,1017,2540 'view':1992 'vue':67,100 'watch':1945 'webhook':1089,1127,2545 'webhooks/custom':281 'week':1795 'well':2512 'withindex':678,714,2117,2221,2347 'without':1345,2173,2189,2437 'work':154,2155,2400 'workflow':62 'wrap':1187 'write':119,259,270,614,765,1012,2296,2448 'write-tim':2447 'written':217 'your-secret-her':1530 'zero':235","prices":[{"id":"8dcca49f-79ee-49f8-a28e-55b540c154c3","listingId":"a3067258-1637-4761-bece-01c7fca42c68","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:35:14.697Z"}],"sources":[{"listingId":"a3067258-1637-4761-bece-01c7fca42c68","source":"github","sourceId":"sickn33/antigravity-awesome-skills/convex","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/convex","isPrimary":false,"firstSeenAt":"2026-04-18T21:35:14.697Z","lastSeenAt":"2026-04-24T06:50:58.307Z"}],"details":{"listingId":"a3067258-1637-4761-bece-01c7fca42c68","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"convex","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34831,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"fc28c888e734646ba7b3d6df59099c4afc92b287","skill_md_path":"skills/convex/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/convex"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"convex","description":"Convex reactive backend expert: schema design, TypeScript functions, real-time subscriptions, auth, file storage, scheduling, and deployment."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/convex"},"updatedAt":"2026-04-24T06:50:58.307Z"}}