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

# Server Functions

> Run server-side JavaScript and TypeScript in your Canvas app — access environment variables, key-value storage, and the Mixpeek API without exposing secrets.

## Overview

Server functions let you run backend logic inside your Canvas app. Write TypeScript or JavaScript handlers that execute server-side with access to environment variables, a built-in KV store, and `fetch` — without managing infrastructure.

***

## How it works

1. Include server function source files in your deploy's `source_files` map
2. Files under `api/` become HTTP endpoints at `/functions/`
3. Canvas transpiles TypeScript → JavaScript via esbuild and executes your handler in a sandboxed async context

| Source file | Endpoint |
| - | - |
| `api/hello.ts` | `GET/POST /functions/hello` |
| `api/search.js` | `GET/POST /functions/search` |
| `api/data/export.ts` | `GET/POST /functions/data/export` |

***

## Writing a server function

Export a default function that receives a context object and returns a response:

```typescript theme={null}
// api/hello.ts
export default async function handler(ctx) {
  const name = ctx.req.query.name || 'world'
  return {
    status: 200,
    body: { message: `Hello, ${name}!` },
  }
}
```

### Context object

Your handler receives a `ctx` object with:

| Property | Type | Description |
| - | - | - |
| `ctx.req.method` | `string` | HTTP method (GET, POST, etc.) |
| `ctx.req.path` | `string` | Request path |
| `ctx.req.query` | `object` | URL query parameters |
| `ctx.req.body` | `any` | Parsed JSON body (for POST/PUT) |
| `ctx.req.headers` | `object` | Request headers (excluding internal headers) |
| `ctx.env` | `object` | App environment variables |
| `ctx.kv` | `object` | Key-value store (see below) |

### Return value

Return an object with:

| Field | Type | Default | Description |
| - | - | - | - |
| `status` | `number` | `200` | HTTP status code |
| `body` | `any` | — | Response body (object → JSON, string → text) |
| `headers` | `object` | `{}` | Custom response headers |

***

## Key-value store

Every app has a built-in Redis-backed KV store, accessible in server functions via `ctx.kv`:

```typescript theme={null}
// api/counter.ts
export default async function handler(ctx) {
  const current = await ctx.kv.get('visit_count')
  const count = parseInt(current || '0') + 1
  await ctx.kv.set('visit_count', String(count))

  return {
    body: { visits: count },
  }
}
```

| Method | Signature | Description |
| - | - | - |
| `get` | `kv.get(key: string): Promise<string \| null>` | Read a value |
| `set` | `kv.set(key: string, value: string, ttl?: number): Promise<void>` | Write a value (optional TTL in seconds, default 30 days) |
| `del` | `kv.del(key: string): Promise<void>` | Delete a key |
| `keys` | `kv.keys(): Promise<string[]>` | List all keys for this app |

***

## Calling the Mixpeek API

Use `fetch` to call the Mixpeek API through the Canvas proxy — credentials are injected automatically:

```typescript theme={null}
// api/search.ts
export default async function handler(ctx) {
  const { query } = ctx.req.body

  const res = await fetch('https://api.mixpeek.com/v1/retrievers/ret_abc123/execute', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${ctx.env.MIXPEEK_API_KEY}`,
      'X-Namespace': ctx.env.MIXPEEK_NAMESPACE_ID,
    },
    body: JSON.stringify({ inputs: { query }, settings: { limit: 10 } }),
  })

  return { body: await res.json() }
}
```

***

## Deploying with source files

Include your server functions in the `source_files` field when deploying:

```bash theme={null}
curl -X POST https://api.mixpeek.com/v1/apps/$APP_ID/deploy \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "cli_upload",
    "bundle_s3_key": "$BUNDLE_KEY",
    "environment": "production",
    "message": "Add search API route",
    "source_files": {
      "api/hello.ts": "export default async function handler(ctx) {\n  return { body: { message: \"Hello!\" } }\n}",
      "api/search.ts": "export default async function handler(ctx) {\n  // search logic here\n}"
    }
  }'
```

***

## Runtime logging

`console.log`, `console.warn`, `console.error`, and `console.info` calls in server functions are captured and sent to the [runtime logs](https://docs.mixpeek.com/docs/canvas/apps/logs.md) system. View them in Studio or query via API.

```typescript theme={null}
// api/process.ts
export default async function handler(ctx) {
  console.log('Processing request', ctx.req.method, ctx.req.path)

  try {
    const result = await doWork(ctx.req.body)
    console.info('Success:', result.id)
    return { body: result }
  } catch (err) {
    console.error('Failed:', err.message)
    return { status: 500, body: { error: err.message } }
  }
}
```

***

## Limitations

* **Execution timeout:** 30 seconds per request
* **Request body size:** 1 MB max
* **No filesystem access:** Server functions run in a sandboxed context
* **No npm imports:** Only `fetch` and the `ctx` APIs are available in the execution context
* **TypeScript only:** `.ts` and `.js` files are supported (transpiled via esbuild)

***

## Related

* [Deploy from Code](https://docs.mixpeek.com/docs/canvas/apps/deploy.md)
* [Runtime Logs](https://docs.mixpeek.com/docs/canvas/apps/logs.md)
* [Environment Variables](https://docs.mixpeek.com/docs/canvas/apps/environment-variables.md)


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