> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boxd.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Convex

> Run boxd machines from your Convex functions, with machine state and command output kept in reactive tables.

<img src="https://mintcdn.com/azin/sB_wy19VO6HgpiRY/images/boxd-x-convex.png?fit=max&auto=format&n=sB_wy19VO6HgpiRY&q=85&s=dfc762c7a0a8d8b2452cff50d6e4fb2e" alt="The banner shows the boxd.sh and Convex logos with the line composable computers on Convex." width="2400" height="1640" data-path="images/boxd-x-convex.png" />

[Convex](https://www.convex.dev) is the open-source reactive backend for TypeScript apps, with a database, server functions, and live queries in one place. [Components](https://www.convex.dev/components) add packaged backend features to a Convex app. The boxd component is [listed in the Convex components directory](https://www.convex.dev/components/boxd-sh/convex), and it lets your Convex functions create, fork, and run commands in boxd machines.

The component keeps a row for every machine and every command it runs. Your UI subscribes to machine state and command output with a plain Convex query, and the query re-runs whenever a row changes.

## Install the component

```bash theme={"theme":"github-dark"}
npm install @boxd-sh/convex
```

Create an API key and set it on your Convex deployment:

```bash theme={"theme":"github-dark"}
boxd auth keys create convex
npx convex env set BOXD_API_KEY bxd_...
```

Then install the component in `convex/convex.config.ts` and bind the key into it:

```typescript convex/convex.config.ts theme={"theme":"github-dark"}
import { defineApp } from "convex/server";
import { v } from "convex/values";
import boxd from "@boxd-sh/convex/convex.config.js";

const app = defineApp({
  env: { BOXD_API_KEY: v.string() },
});

app.use(boxd, { env: { BOXD_API_KEY: app.env.BOXD_API_KEY } });

export default app;
```

The key lives in the component's own environment, so your functions never pass it as an argument. The component exchanges it for a session token once and reuses that token until it nears expiry.

<Note>
  Every boxd API key is fenced to one organization. Machines are created in that org and billed to it. In a brand-new Convex project, run `npx convex dev` once before setting the key, so there is a deployment to set it on.
</Note>

## Run machines from your functions

Calls that reach boxd run in actions, and reads run in queries:

```typescript convex/machines.ts theme={"theme":"github-dark"}
import { Boxd } from "@boxd-sh/convex";
import { v } from "convex/values";
import { components } from "./_generated/api";
import {
  action,
  query,
  type ActionCtx,
  type QueryCtx,
} from "./_generated/server";

const boxd = new Boxd(components.boxd);

// Derive the owner from your auth, never from a client argument.
async function ownerId(ctx: QueryCtx | ActionCtx) {
  const identity = await ctx.auth.getUserIdentity();
  if (!identity) throw new Error("Unauthenticated");
  return identity.subject;
}

export const createMachine = action({
  args: {},
  handler: async (ctx) => {
    return await boxd.create(ctx, {
      ownerId: await ownerId(ctx),
      vcpu: 1,
      autoSuspendSeconds: 300,
    });
  },
});

export const run = action({
  args: { machineId: v.string(), command: v.string() },
  handler: async (ctx, { machineId, command }) => {
    return await boxd.exec(ctx, {
      ownerId: await ownerId(ctx),
      machineId,
      command,
    });
  },
});

// Reactive. Re-runs whenever one of this user's machine rows changes.
export const myMachines = query({
  args: {},
  handler: async (ctx) => boxd.list(ctx, { ownerId: await ownerId(ctx) }),
});

// Reactive. Every command's status and output, newest first.
export const history = query({
  args: { machineId: v.string() },
  handler: async (ctx, { machineId }) =>
    boxd.listExecutions(ctx, { machineId, ownerId: await ownerId(ctx) }),
});
```

`create` and `fork` wait until the new machine accepts a command, and both return in under a second. A machine on standby or hibernated wakes by itself when it gets a command or an HTTPS request, so `exec` works without a `resume` first.

## What the component can do

| Method | On boxd |
| - | - |
| `create` | A new machine with 1, 2, 4, or 8 vCPU, which boxd pairs with 4, 8, 16, or 32 GiB. Takes `image`, `env`, `autoSuspendSeconds`, `autoDestroySeconds`, and `isolated`. |
| `fork` | A live copy of the machine, disk and memory, owned by the same owner. |
| `exec` | Runs a command, waits for it to exit, and records it in the execution table. |
| `readFile`, `writeFile`, `listDir` | Files in and out of the machine, up to 8 MiB per call. |
| `expose` | Routes public HTTPS to a port and returns the `https://<name>.boxd.sh` URL. |
| `pause`, `resume` | Puts the machine on standby, with memory kept in RAM, and brings it back. |
| `hibernate`, `wake` | Writes memory to disk and releases the RAM, then loads it back. |
| `stop`, `start`, `destroy` | Shuts down with the disk kept, cold boots, or deletes the machine. |
| `get`, `list`, `listExecutions` | Reactive reads over machine rows and command history. |

Errors arrive as a `ConvexError` with a stable code such as `NOT_FOUND`, `CONFLICT`, or `RATE_LIMITED`. Branch on the code with `isBoxdError`.

## Scope machines to your users

Pass an `ownerId` on every call. A machine created with an `ownerId` is reachable only with that same `ownerId`. For any other owner, reads return `null` or an empty list, and actions fail with `NOT_FOUND`, the same as for a machine that does not exist. A fork inherits the owner of its source machine.

For code you did not write, create the machine with `isolated: true`. Isolation removes the in-machine `boxd` CLI, the metadata endpoint, integrations, and agent logins, and keeps the machine out of the org's default network. The machine keeps outbound internet unless you set an [egress allowlist](/guides/egress).

## Limits

Convex stops an action after 10 minutes. `exec` kills its command after `timeoutMs`, which defaults to 9 minutes and goes up to 9.5. For longer work, start the command in the background with `nohup ... &` and check on it with later `exec` calls.

`exec` returns up to 2 million characters per stream, and the execution row keeps the first 64,000.

boxd can change a machine without a call through the component, for example when auto-suspend kicks in. Call `refresh` to bring that change into the row, for instance on a timer while a machine is on screen.

The component ships as [`@boxd-sh/convex`](https://www.npmjs.com/package/@boxd-sh/convex) and is [open source](https://github.com/azin-tech/boxd-convex) under the MIT license. The [README](https://github.com/azin-tech/boxd-convex#readme) covers the full API, the error codes, and testing with `convex-test`.


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