> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/get-convex/convex-backend/llms.txt
> Use this file to discover all available pages before exploring further.

# Mutation functions

> API reference for defining and using Convex mutation functions

Mutations allow you to write data to your Convex database. All operations within a mutation are atomic and isolated.

## Defining mutations

### mutation

Define a public mutation function that can be called from clients.

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

export const createTask = mutation({
  args: {
    text: v.string(),
    completed: v.optional(v.boolean()),
  },
  returns: v.id("tasks"),
  handler: async (ctx, args) => {
    const taskId = await ctx.db.insert("tasks", {
      text: args.text,
      completed: args.completed ?? false,
    });
    return taskId;
  },
});
```

<ParamField path="args" type="PropertyValidators" optional>
  Argument validation object using validators from `convex/values`.

  ```typescript theme={null}
  args: {
    taskId: v.id("tasks"),
    completed: v.boolean(),
  }
  ```
</ParamField>

<ParamField path="returns" type="Validator" optional>
  Return value validator for type safety and validation.

  ```typescript theme={null}
  returns: v.id("tasks")
  ```
</ParamField>

<ParamField path="handler" type="function" required>
  The implementation function that receives a `MutationCtx` and validated arguments.

  <ParamField path="ctx" type="MutationCtx">
    Mutation context with read-write database access.
  </ParamField>

  <ParamField path="args" type="object">
    Validated arguments matching the `args` validator.
  </ParamField>
</ParamField>

### internalMutation

Define an internal mutation that can only be called from other Convex functions.

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

export const deleteUser = internalMutation({
  args: { userId: v.id("users") },
  returns: v.null(),
  handler: async (ctx, args) => {
    await ctx.db.delete(args.userId);
    return null;
  },
});
```

Internal mutations are recommended for:

* Mutations called from actions or scheduled functions
* Administrative operations
* Mutations that should not be exposed to clients

## Mutation context

### MutationCtx

The context object passed to mutation handlers.

<ResponseField name="db" type="DatabaseWriter">
  Read-write database interface. Provides all read methods plus `insert`, `patch`, `replace`, and `delete`.

  ```typescript theme={null}
  // Insert a document
  const id = await ctx.db.insert("tasks", { text: "Buy milk" });

  // Update specific fields
  await ctx.db.patch(id, { completed: true });

  // Replace entire document
  await ctx.db.replace(id, { text: "Buy milk", completed: true });

  // Delete a document
  await ctx.db.delete(id);
  ```

  See [Database API](/api/server/database) for complete details.
</ResponseField>

<ResponseField name="auth" type="Auth">
  Authentication interface to get the current user's identity.

  ```typescript theme={null}
  const identity = await ctx.auth.getUserIdentity();
  if (identity === null) {
    throw new Error("Not authenticated");
  }
  const userId = identity.subject;
  ```
</ResponseField>

<ResponseField name="storage" type="StorageWriter">
  File storage interface with read and write capabilities.

  ```typescript theme={null}
  // Generate upload URL for client
  const uploadUrl = await ctx.storage.generateUploadUrl();

  // Delete a file
  await ctx.storage.delete(storageId);
  ```

  See [Storage API](/api/server/storage) for details.
</ResponseField>

<ResponseField name="scheduler" type="Scheduler">
  Schedule functions to run in the future.

  ```typescript theme={null}
  // Run immediately after this mutation commits
  await ctx.scheduler.runAfter(0, internal.emails.send, { userId });

  // Run in 24 hours
  await ctx.scheduler.runAfter(24 * 60 * 60 * 1000, internal.cleanup.run, {});
  ```

  See [Scheduler API](/api/server/scheduler) for details.
</ResponseField>

<ResponseField name="runQuery" type="function">
  Call a query function within the same transaction.

  ```typescript theme={null}
  const user = await ctx.runQuery(internal.users.get, { userId });
  ```

  The query runs within the same transaction, seeing a consistent snapshot of the database.
</ResponseField>

<ResponseField name="runMutation" type="function">
  Call a mutation function within the same transaction.

  ```typescript theme={null}
  await ctx.runMutation(internal.analytics.track, { event: "task_created" });
  ```

  The mutation runs in a sub-transaction. If it throws an error, all of its writes will be rolled back.
</ResponseField>

## Database operations

Mutations have access to all database write operations:

### insert

Insert a new document into a table.

```typescript theme={null}
const userId = await ctx.db.insert("users", {
  name: "Alice",
  email: "alice@example.com",
});
```

### patch

Shallow merge updates into an existing document.

```typescript theme={null}
// Update only the "name" field, leaving other fields unchanged
await ctx.db.patch(userId, { name: "Alice Smith" });

// Remove an optional field by setting it to undefined
await ctx.db.patch(userId, { nickname: undefined });
```

### replace

Completely replace a document with new values.

```typescript theme={null}
await ctx.db.replace(userId, {
  name: "Bob",
  email: "bob@example.com",
});
```

### delete

Delete a document from the database.

```typescript theme={null}
await ctx.db.delete(userId);

// Delete multiple documents
const oldTasks = await ctx.db
  .query("tasks")
  .withIndex("by_completed", (q) => q.eq("completed", true))
  .collect();
for (const task of oldTasks) {
  await ctx.db.delete(task._id);
}
```

## Transaction guarantees

Convex guarantees that all operations within a single mutation are:

<Card title="Atomic" icon="atom">
  All writes either succeed together or fail together. You never have to worry about partial writes leaving your data in an inconsistent state.
</Card>

<Card title="Isolated" icon="lock">
  Each mutation sees a consistent snapshot of the database. Concurrent mutations don't interfere with each other.
</Card>

<Card title="Serializable" icon="list-ol">
  Mutations execute as if they ran one at a time in some order, even when running concurrently.
</Card>

## Best practices

<Card title="Always validate arguments" icon="shield-check">
  For security, add argument validation to all public mutations in production apps.
</Card>

<Card title="Use internal mutations" icon="lock">
  For mutations called only from actions or scheduled functions, use `internalMutation` to prevent direct client calls.
</Card>

<Card title="Keep mutations focused" icon="target">
  Each mutation should do one logical operation. Break complex operations into multiple mutations if needed.
</Card>

<Card title="Return useful values" icon="arrow-left">
  Return the new document ID or other useful information for the client.
</Card>
