# helix.config.ts reference

> Every key helix.config.ts accepts today: name, projectId, workspaceId, environment, and authentications, with types and semantics.

`helix.config.ts` declares a Helix project's identity and its authentication aliases. The CLI reads it at build time, the dev server at startup, and the SDK at runtime. A project has one config file: it names the project, the workspace and project IDs the CLI works against, and the environment those IDs live in.

## Type definition

```typescript
// @trayai/helix-sdk

interface HelixConfig {
  name: string;          // project name, used when the first deploy provisions
  workspaceId: string;   // UUID of the Tray workspace
  projectId?: string;    // UUID of the provisioned project
  environment?: string;  // Helix environment, for example 'us1'

  authentications?: Record<string, string>;  // alias to auth UUID
}
```

Export the object with `defineConfig` so the compiler checks the shape:

```typescript
// helix.config.ts
import { defineConfig } from '@trayai/helix-sdk';

export default defineConfig({
  name: 'customer-health',
  workspaceId: 'f8e7d6c5-4b3a-2190-8765-abcdef012345',
});
```

## Keys

| Key | Type | Required | Purpose |
|---|---|---|---|
| `name` | `string` | Yes | The project name. `helix init` writes it, and the first `helix deploy` uses it when it provisions the project. |
| `workspaceId` | `string` (UUID) | Yes | Ties the project to a Tray workspace. Determines which authentications resolve, locally and on deploy. |
| `projectId` | `string` (UUID) | To deploy only | The provisioned project this checkout points at. Names the production subdomain and the resources a deploy provisions. |
| `environment` | `string` | No | The Helix environment the CLI talks to, for example `us1`. Written by `helix env set`. |
| `authentications` | `Record<string, string>` | No | Maps human-readable aliases to auth UUIDs. Used as `ctx.http.authed('alias')`. |

### name

The project's name. `helix init [project-name]` writes it into the scaffold. On the first `helix deploy` the platform provisions a project under this name, so it's the label you see in the dashboard's Projects list. The deploy also generates an AI description of the project, and regenerates it on every later deploy.

`helix deploy --name <name>` overrides the config value for that one deploy.

### workspaceId

Required UUID. The workspace matters both locally and on deploy: `ctx.http.authed('alias')` resolves against the workspace's auth service even during `helix dev`, and agent tooling asks the workspace which authentications are available.

Set it with `helix workspace select` (interactive picker) or `helix workspace set <id>` (when you already know the ID), or pass `helix init --workspace-id <id>` at scaffold time.

### projectId

Optional UUID until you deploy. Nothing is provisioned when you run `helix init`, so a fresh project has no ID: the first `helix deploy` provisions one, and later deploys update that project in place. Set it yourself with `helix project set <id>` to point a checkout at an existing project, or pass `helix init --project-id <id>`.

The project ID names the production subdomain, `https://{project-id}.helix-app.ai`, and the resources provisioned for the project. It's also what `helix dev` needs to reach persistent key-value storage: with no project ID, local KV is in-memory and resets when you restart the dev server.

### environment

The Helix environment the CLI talks to, written by `helix env set <environment>` and persisted for later commands. `us1` is the environment shown in that command's help text. This is separate from the `--env <us1|staging>` flag on `login`, `logout`, and `whoami`, which selects the environment for a single session command and doesn't read the config file. See [the configuration model](/documentation/concepts/configuration/).

### authentications

Maps aliases to auth UUIDs stored in Helix. Your code references the alias (`ctx.http.authed('salesforce_prod')`); the UUID points to a credential record on Helix's servers, and all credential injection happens server-side through the auth proxy. Credentials themselves never appear in this file, which is why the mapping is safe to commit.

Write entries with `helix auth connect` (interactive) or `helix auth add <alias> <uuid>` (when you know the UUID). Authentications are created in Tray iPaaS today, not in Helix. Calling `authed()` with an alias missing from this map throws immediately, and the error lists the aliases that are available.

## Complete example

```typescript
// helix.config.ts
import { defineConfig } from '@trayai/helix-sdk';

export default defineConfig({
  // Project name. The first deploy provisions a project under this name.
  name: 'customer-health',

  // Workspace UUID (required). Auth aliases resolve against this
  // workspace, locally and on deploy.
  workspaceId: 'f8e7d6c5-4b3a-2190-8765-abcdef012345',

  // Project UUID. Written by the first deploy, or by helix project set.
  projectId: 'a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d',

  // Helix environment. Written by helix env set.
  environment: 'us1',

  // Alias to auth UUID. Use as ctx.http.authed('salesforce_prod').
  authentications: {
    salesforce_prod: '1a0fbf5c-2c9e-4aa1-ada3-ccbba65019ab',
    openai: 'ee41bc90-1234-5678-9abc-def012345678',
  },
});
```

## What does not go in this file

| Concern | Where it lives |
|---|---|
| Credential values and injection rules | Helix's servers, alongside the credential records. Config holds only alias-to-UUID mappings |
| Your Tray session token | `~/.tray.config`, written by `helix login` and shared with `connector-cli` |
| Function-level settings (input schemas, handlers) | The function files, via `defineFunction` |
| Who can open the deployed app | The project's Access Control tab in the dashboard, not a code or config construct |
| Infrastructure settings (region, runtime, memory) | The workspace, not the project |

## TypeScript path aliases

Use tsconfig path mapping so imports work from any directory depth. The canonical convention is `@project/*`:

```json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@project/*": ["./*"]
    }
  },
  "exclude": ["node_modules", ".helix"]
}
```

```typescript
// functions/api/v1/contacts/index.get.ts
import { lookupContact } from '@project/functions/_shared/contacts';
```

The SDK and CLI respect any path mapping configured in `tsconfig.json`; other conventions such as `@/lib/*` work too. Pick one and apply it consistently.

## Roadmap: keys the shipped product does not accept

:::roadmap{title="Everything below is design, not shipped"}
`helix.config.ts` accepts `name`, `workspaceId`, `projectId`, `environment`, and `authentications` today, and nothing else. The blocks in this section come from the platform design: adding one to your config does not turn the feature on. They're documented here so the shape is known when the features land. See [limits, defaults, and roadmap](/documentation/reference/limits/).
:::

The designed shape adds six more keys, plus a `ConfigValue` type that allows a thunk anywhere a string is accepted:

```typescript
// Design only. Not accepted by the shipped CLI.

// A literal string, or a thunk evaluated once when the config file loads.
type ConfigValue = string | (() => string);

interface HelixConfig {
  databases?: Record<string, {
    type: 'postgres' | 'mysql' | 'mssql';
    auth: string;                          // UUID of a credential record
    schema?: string;                       // path to a Drizzle schema file
  }>;

  kvStores?: Record<string, {
    type: 'redis';
    auth: string;
  }>;

  queues?: Record<string,
    {} |                                   // managed queue (empty object)
    {
      type: 'redis' | 'rabbitmq' | 'kafka';
      auth: string;
    }
  >;

  roles?: Record<string, string>;          // role ID to display name

  mcp?: McpConfig;                         // MCP server configuration

  config?: Record<string, ConfigValue>;    // values surfaced on ctx.config
}
```

### databases

Named connections to databases outside Helix's managed infrastructure, used as `ctx.db('alias')`. Helix ships no managed database and no `ctx.db()`, so nothing in this block resolves today.

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | `'postgres' \| 'mysql' \| 'mssql'` | Yes | Database engine. The design marks `mssql` as a later addition than the other two. |
| `auth` | `string` (UUID) | Yes | Credential record in the Helix auth service. |
| `schema` | `string` | No | Path to a Drizzle schema file (for example `'db/customer-pg.schema.ts'`). Providing it turns on typed queries and Drizzle Kit migrations for this connection. |

The managed database has no entry in the file. Its schema lives in `db/schema.ts` using Drizzle ORM.

### kvStores

Named connections to external key-value stores, used as `ctx.kv('alias')`. Each entry has a `type` (`'redis'`, with `memcached` and `dynamodb` designed for later) and an `auth` UUID pointing at a credential record. Aliases must not collide with the managed scope keywords, because `ctx.kv()` resolves scope keywords first.

The shipped key-value store is project-scoped, takes no alias, and has no external backends. See [the key-value store guide](/documentation/guides/key-value-store/).

### queues

Every queue the project touches is declared here, managed and external, so the CLI has a complete inventory for provisioning and a typo can't silently create a queue. Calling `ctx.queue('name')` with an undeclared name throws at startup.

| Entry shape | Meaning |
|---|---|
| `{}` (empty object) | Managed queue. Helix provisions it: in-memory during `helix dev`, SQS in production. |
| `{ type, auth }` | External queue. The Helix proxy resolves credentials from the auth service and connects to the external backend. `redis` first, with `rabbitmq` and `kafka` designed for later. |

Consumers live in `functions/_queues/<name>.ts`, where the filename matches the queue name. HTTP is the only trigger a shipped function can have, so no queue consumer runs today.

### roles

A flat map declaring the project's authorization vocabulary. The key is the role ID, referenced in per-function `access` exports and surfaced in `ctx.identity.user.roles`. The value is the display name shown in the dashboard.

In the design, `helix deploy` registers the map with the platform and the dashboard offers exactly these roles for assignment, validating role IDs at build time. In the shipped product, app access is a dashboard setting on the project (Workspace, Only people invited, or Organization) and there is no role map and no code construct. See [identity and roles](/documentation/guides/identity-and-roles/).

### mcp

Exposes selected functions as Model Context Protocol tools that AI agents can discover and call, served per project. Helix ships an MCP server *for* the CLI, which agents use to work on a project; exposing a project's own functions as tools is design only.

| Field | Type | Required | Description |
|---|---|---|---|
| `enabled` | `boolean` | Yes | Turns the MCP server on or off for this project. |
| `tools` | `string[]` | Yes | Function paths to expose, relative to `functions/`, without a method suffix. `'tools/lookup-customer'` maps to `functions/tools/lookup-customer.ts`. |
| `server` | `object` | No | Server metadata shown to MCP clients. |
| `server.name` | `string` | No | Display name of the MCP server. |
| `server.description` | `string` | No | What the toolset does. |
| `server.version` | `string` | No | Semantic version of the toolset. |
| `auth` | `object` | No | Authentication requirements for tool calls. |
| `auth.required` | `boolean` | No | When `true`, every tool call must authenticate. |
| `auth.methods` | `('helix-identity' \| 'api-key' \| 'oauth')[]` | No | Accepted authentication methods. |
| `rateLimit` | `object` | No | Rate limits applied to MCP tool calls. |
| `rateLimit.requestsPerMinute` | `number` | No | Maximum tool calls per minute. |
| `rateLimit.requestsPerHour` | `number` | No | Maximum tool calls per hour. |
| `rateLimit.concurrent` | `number` | No | Maximum concurrent tool invocations. |

Each exposed function also declares a `tool` named export with its MCP name, description, and input schema. Individual tools can override the server-level rate limit with a `rateLimit` export.

### config

Key-value pairs surfaced on `ctx.config` in every function. Values resolve to a flat `Record<string, string>`: `ctx.config.maxRetries` is always `'3'`, never `3`. All-string values mean a secret from the process environment flows through without a coercion step, and a value behaves the same whether it came from a literal or a thunk. There is no `ctx.config` in the shipped SDK.

### ConfigValue and secrets

`ConfigValue` is `string | (() => string)`. Thunks are evaluated once, when the config file is loaded, so `ctx.config` and `ctx.http.authed()` only ever see resolved strings. The design pairs them with `requireEnv` to keep secrets out of the committed file:

```typescript
// Design only. Not accepted by the shipped CLI.
import { defineConfig, requireEnv } from '@trayai/helix-sdk';

export default defineConfig({
  workspaceId: 'f8e7d6c5-4b3a-2190-8765-abcdef012345',
  config: {
    internalSecret: () => requireEnv('INTERNAL_SECRET'),
  },
});
```

`requireEnv` throws if the variable is missing, so a forgotten secret fails fast at load time instead of becoming a silent empty string. The underlying values are set per project with `helix vars set`, which the shipped CLI does not have either. The shipped config accepts plain strings only.

### Per-target config files

The design gives a project one config file per deploy target, with no environment map, no merging, and no active-environment state: a different target is a different file.

```
helix.config.ts               default; the target you develop against
helix.staging.config.ts
helix.production.config.ts
```

Resolution precedence, highest first:

| Precedence | Source | Example |
|---|---|---|
| 1 | `--config <path>` flag | `helix deploy --config helix.production.config.ts` |
| 2 | `HELIX_CONFIG` environment variable | `HELIX_CONFIG=helix.staging.config.ts helix build` |
| 3 | `./helix.config.ts` | The default when neither is set |

Config files are ordinary TypeScript modules, so shared values can be exported from a shared module and spread into each target file.

The shipped CLI has no `--config` flag and reads no `HELIX_CONFIG` variable. One project has one `helix.config.ts`, and `helix env set` chooses the environment it points at.

---

Canonical: https://helix.tray.ai/documentation/reference/configuration/
Any link on this page is available as markdown by appending .md to its URL.
Full corpus: https://helix.tray.ai/documentation/llms-full.txt