> ## Documentation Index
> Fetch the complete documentation index at: https://vlyai-1c28d863.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Convex backend

> Convex is the reactive backend that vly apps run on. Real-time queries, end-to-end TypeScript, queries / mutations / actions, file storage, vector search, and more.

Every app vly generates runs on **Convex** — a managed real-time backend with a serverless function model and a TypeScript-first developer experience. This page is the executive summary; for the full deep-dive, see [Convex Deep Dive](/convex/overview).

## Why Convex

<CardGroup cols={2}>
  <Card title="Reactive by default" icon="zap">
    Every Convex query auto-updates on the client when underlying data changes. No polling, no websocket plumbing, no `refetch` calls. Build a chat or a dashboard, and it's live without effort.
  </Card>

  <Card title="End-to-end TypeScript" icon="code-2">
    The schema is TypeScript. Queries return typed results. Your React component consumes the same types. No DTO mapping, no codegen, no client/server drift.
  </Card>

  <Card title="Serverless functions, no infra" icon="server-cog">
    Queries, mutations, actions, and scheduled functions run on Convex's managed runtime. No containers to ship, no databases to provision.
  </Card>

  <Card title="Native primitives for hard things" icon="boxes">
    File storage, vector search, full-text search, scheduled jobs, transactional mutations — all first-class, not bolted on.
  </Card>
</CardGroup>

## The four function types

<CardGroup cols={2}>
  <Card title="Queries" icon="search" href="/convex/queries">
    Read data. Reactive — clients subscribe and get updates automatically. Cannot mutate data.
  </Card>

  <Card title="Mutations" icon="pencil" href="/convex/mutations">
    Write data, transactionally. ACID guarantees. Cannot call third-party APIs.
  </Card>

  <Card title="Actions" icon="zap" href="/convex/actions">
    Call third-party APIs, run long-running work. Use `process.env`. Can run mutations and queries internally.
  </Card>

  <Card title="Scheduled functions" icon="clock" href="/convex/scheduled-functions">
    Cron-style or one-shot delayed execution. Common for retries, cleanups, reminders.
  </Card>
</CardGroup>

## A minimal example

The schema:

```typescript convex/schema.ts theme={null}
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  tasks: defineTable({
    title: v.string(),
    completed: v.boolean(),
    ownerId: v.id("users"),
    dueAt: v.optional(v.number()),
  })
    .index("by_owner", ["ownerId"])
    .index("by_owner_and_completed", ["ownerId", "completed"]),

  users: defineTable({
    email: v.string(),
    name: v.string(),
    avatarUrl: v.optional(v.string()),
    createdAt: v.number(),
  }).index("by_email", ["email"]),
});
```

A query:

```typescript convex/tasks.ts theme={null}
import { query } from "./_generated/server";
import { v } from "convex/values";

export const listForOwner = query({
  args: { ownerId: v.id("users"), onlyOpen: v.optional(v.boolean()) },
  handler: async (ctx, { ownerId, onlyOpen }) => {
    const q = ctx.db
      .query("tasks")
      .withIndex(
        onlyOpen ? "by_owner_and_completed" : "by_owner",
        (q) => onlyOpen ? q.eq("ownerId", ownerId).eq("completed", false)
                        : q.eq("ownerId", ownerId),
      );
    return await q.collect();
  },
});
```

Call it from React:

```tsx theme={null}
const tasks = useQuery(api.tasks.listForOwner, { ownerId, onlyOpen: true });
```

A mutation:

```typescript convex/tasks.ts theme={null}
import { mutation } from "./_generated/server";
import { v } from "convex/values";

export const create = mutation({
  args: {
    title: v.string(),
    ownerId: v.id("users"),
    dueAt: v.optional(v.number()),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert("tasks", {
      ...args,
      completed: false,
    });
  },
});

export const toggle = mutation({
  args: { id: v.id("tasks") },
  handler: async (ctx, { id }) => {
    const task = await ctx.db.get(id);
    if (!task) throw new Error("Task not found");
    await ctx.db.patch(id, { completed: !task.completed });
  },
});
```

A React component using both:

```tsx components/TaskList.tsx theme={null}
import { useQuery, useMutation } from "convex/react";
import { api } from "../convex/_generated/api";

export function TaskList({ ownerId }: { ownerId: Id<"users"> }) {
  const tasks  = useQuery(api.tasks.listForOwner, { ownerId, onlyOpen: true });
  const toggle = useMutation(api.tasks.toggle);

  if (tasks === undefined) return <div>Loading…</div>;

  return (
    <ul>
      {tasks.map((task) => (
        <li key={task._id}>
          <input
            type="checkbox"
            checked={task.completed}
            onChange={() => toggle({ id: task._id })}
          />
          {task.title}
        </li>
      ))}
    </ul>
  );
}
```

When `toggle` runs, every connected client viewing the same query updates immediately. No refetch, no manual invalidation.

## How vly uses Convex

vly maps app concepts onto Convex concepts:

```mermaid theme={null}
graph TB
    P[Your prompt]
    SC[Convex schema<br/>defineSchema + defineTable]
    QU[Convex queries<br/>read paths in your UI]
    MU[Convex mutations<br/>write paths in your UI]
    AC[Convex actions<br/>third-party API calls]
    AU[Convex auth<br/>email + OAuth]
    FS[Convex file storage<br/>uploads + serving]
    UI[React components<br/>useQuery + useMutation]
    EX[External services<br/>Stripe / Resend / OpenAI]

    P --> SC
    P --> AU
    P --> UI
    SC --> QU
    SC --> MU
    QU --> UI
    MU --> UI
    AU --> UI
    AC --> EX
    EX --> AC
    AC --> MU
    FS --> UI

    style P fill:#EDE9FE,stroke:#6D28D9
    style SC fill:#FFFFFF,stroke:#6D28D9
    style UI fill:#CFFAFE,stroke:#06B6D4
```

When you ask vly to "send an email when a task is assigned," vly creates a Convex action (because actions can call external APIs), wires it into the assignment mutation, and adds the API key to your environment.

## When you'll edit Convex code

Most of the time, you won't — vly handles it. But there are good reasons to drop into Code mode and edit a Convex file directly:

<AccordionGroup>
  <Accordion title="Adding an index for performance" icon="zap">
    A query is slow. You add `.index("by_field", ["fieldName"])` to the schema, then re-prompt or hand-edit the query to use it. See [Indexes](/convex/indexes).
  </Accordion>

  <Accordion title="Tweaking validation" icon="shield">
    Convex schema validators (`v.string()`, `v.optional(...)`, `v.union(...)`) define what data shapes are allowed. Tightening or loosening these by hand is sometimes faster than prompting.
  </Accordion>

  <Accordion title="Custom action logic" icon="zap">
    Calling a third-party API with non-trivial logic — retries, custom serialization, complex auth flows. Hand-edit the action.
  </Accordion>

  <Accordion title="Reading the migration history" icon="history">
    `convex/_generated/` shows the current schema state; the schema files show your authored intent. When debugging schema drift, read both. See [Migrations](/convex/migrations).
  </Accordion>
</AccordionGroup>

## Limits

Convex isn't infinite. The current limits:

<CodeGroup>
  ```text Document size theme={null}
  1 MB max per document
  ```

  ```text Function execution theme={null}
  10 seconds for queries/mutations,
  10 minutes for actions
  ```

  ```text Real-time subscriptions theme={null}
  ~10,000 concurrent subscribers per query
  (soft limit; contact support for higher)
  ```

  ```text Storage theme={null}
  Generous; usage-billed on paid plans.
  File uploads max 100 MB per file (default).
  ```
</CodeGroup>

These are well above what most vly apps need. If you're approaching one, see [Architecture: rate limiting](/architecture/rate-limiting) and [Patterns for scale](/architecture/multi-tenancy).

## Next

<CardGroup cols={3}>
  <Card title="Convex deep dive" icon="database-zap" href="/convex/overview">
    The full reference: schema, queries, mutations, actions, search, storage.
  </Card>

  <Card title="Real-time sync" icon="zap" href="/features/data/realtime-sync">
    How Convex's reactive sync works under the hood.
  </Card>

  <Card title="Data modeling patterns" icon="layers" href="/architecture/data-modeling">
    Schema patterns for the most common app shapes.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.