# Apex bindings and expressions (/docs/core/apex/bindings)



The helpers on this page are exported by `@kysoql/core` and become available
after `.apex()` or `.dynamicApex()`. They describe expressions that your Apex
caller will provide at runtime.

## Scalar and collection binds [#scalar-and-collection-binds]

```ts
import { apexBind } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select(["Id", "Name"])
  .apex()
  .where((eb) =>
    eb.or([
      eb("Name", "=", apexBind<string>("filters.accountName")),
      eb("Id", "in", apexBind<readonly string[]>("accountIds")),
    ]),
  )
  .compile();
```

`apexBind<T>(expression)` accepts an Apex identifier or dotted member path.
Leave off the leading colon. Calls, indexing, whitespace, and arbitrary
expression text are rejected.

The generic `T` checks compatibility with the surrounding query. It cannot prove
that the Apex variable exists or has a valid value at runtime.

## Limits and offsets [#limits-and-offsets]

```ts
import { apexBind } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .limit(apexBind<number>("page.rowLimit"))
  .offset(apexBind<number>("page.rowOffset"))
  .compile();
```

Literal limits and offsets are validated by Kysoql. Bound values only exist in
Apex, so validate their runtime range there.

## Addition and concatenation [#addition-and-concatenation]

Use `apexAdd()` for supported string concatenation or numeric addition:

```ts
import { apexAdd, apexBind } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .where("Name", "=", apexAdd("Ac", "me"))
  .limit(apexAdd(apexBind<number>("page.baseLimit"), 1))
  .compile();
```

This helper is intentionally small. It is not an arbitrary Apex expression
parser.

## String substring [#string-substring]

```ts
import { apexAdd, apexBind, apexSubstring } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .where(
    "Name",
    "like",
    apexAdd(apexSubstring(apexBind<string>("filters.name"), 0, 2), "%"),
  )
  .compile();
```

`apexSubstring()` accepts a string literal or string-valued bind expression and
non-negative literal indices. Runtime string length still belongs to the Apex
caller.

## Read a field from a single-record query [#read-a-field-from-a-single-record-query]

```ts
import { apexBind, apexQueryField } from "@kysoql/core";
import { db } from "./db";

const sourceAccount = db
  .selectFrom("Account")
  .select("Name")
  .apex()
  .where("Id", "=", apexBind<string>("sourceAccount.Id"));

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .where("Name", "=", apexQueryField(sourceAccount, "Name"))
  .compile();
```

`apexQueryField()` models Apex bracket-query field access. Kysoql does not add
`LIMIT 1`, so make sure the inner query is constrained to exactly one record.

## Bind-left INCLUDES [#bind-left-includes]

Apex also supports Kysoql's bind-left `includes` overload:

```ts
import { apexBind } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .where(apexBind<string>("account.Type"), "includes", [
    "Customer - Direct; Customer - Channel",
  ])
  .compile();
```

This is a specific overload for `includes`, not a general bind-left filter API.

## Binds in child subqueries [#binds-in-child-subqueries]

Enter Apex before creating the child subquery when its filters need binds:

```ts
import { apexBind } from "@kysoql/core";
import { db } from "./db";

const compiled = db
  .selectFrom("Account")
  .select("Id")
  .apex()
  .selectSubquery("Contacts", (contacts) =>
    contacts
      .select(["Id", "LastName"])
      .where("LastName", "like", apexBind<string>("filters.lastName")),
  )
  .compile();
```

Child builders remain child builders. They do not gain root-only Apex features.
Knowledge article Apex queries also reject bind expressions.

See [Compile for Apex](/docs/core/apex/overview) for context rules and
[support boundaries](/docs/core/reference/limitations) for broader restrictions.
