docId: trino-client

source: trino-client

slug: trino-client

title: Trino Client

documentType: unknown

contentOrigin: static-doc

content:
---
title: Trino Client
navTitle: Trino Client
description: HTTP client for Trino's REST API.
entrypoint: /docs/trino-client/overview/introduction
---

description: HTTP client for Trino's REST API.

navTitle: Trino Client

keywords: client trino trinos


docId: trino-client/configuration/client-setup

slug: configuration/client-setup

title: Client Setup

text: Basic Authentication

text: Bearer Token Authentication

text: Retry Configuration

text: Timeout

text: Default Headers

content:
---
title: Client Setup
description: Configuration options and authentication for the Trino client.
---

## Basic Authentication

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: {
    type: "basic",
    username: "analyst",
    password: "s3cr3t",
  },
  catalog: "hive",
  schema: "sales",
})
```

The username and password are Base64-encoded and sent as an `Authorization: Basic ...` header on every request.

## Bearer Token Authentication

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: {
    type: "bearer",
    token: "eyJhbGciOiJSUzI1NiIs...",
  },
  catalog: "iceberg",
  source: "my-etl-service",
})
```

The token is sent as an `Authorization: Bearer ...` header.

## Retry Configuration

The client automatically retries on transient failures (HTTP 429, 500, 502, 503, 504 and network errors). Configure retry behavior via the `retry` option:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  retry: {
    maxRetries: 5,
    initialDelay: 500,
    maxDelay: 30000,
    backoffMultiplier: 2,
  },
})
```

<InterfaceReference file="trino-client/src/retry" name="RetryConfig" />

## Timeout

Set a default timeout (in milliseconds) for all requests. If a request exceeds this duration, it will be aborted:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  timeout: 30_000, // 30 seconds
})
```

You can also pass a per-query `signal` for more fine-grained control — see [Executing Queries](/docs/trino-client/queries/executing-queries).

## Default Headers

On construction, the client sets the following Trino headers automatically:

| Header            | Value                                         |
| ----------------- | --------------------------------------------- |
| `X-Trino-Source`  | The `source` option, or `"nodejs"` if omitted |
| `X-Trino-Catalog` | The `catalog` option                          |
| `X-Trino-Schema`  | The `schema` option (only if provided)        |

You can modify headers after construction using `setHeader()` or `setRawHeader()`:

```ts
client.setHeader("X-Trino-Schema", "production")
client.setRawHeader("X-Custom-Header", "value")
```

keywords: authentication client configuration setup options


slug: metadata/inspecting-catalogs

title: Inspecting Catalogs

text: Overview

text: schemas

text: tables

text: views

text: columns

text: Full Discovery Example

content:
---
title: Inspecting Catalogs
description: List schemas, tables, views, and columns from any Trino catalog.
---

## Overview

The Trino client provides convenience methods for inspecting catalog metadata. Each method executes a SQL query internally and returns a simplified result — typically an array of strings or tuples.

See the [API Reference](/docs/trino-client/api-reference) for full method signatures and return types.

## schemas

Lists all schemas in a catalog.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const schemas = await client.schemas({ catalog: "hive" })
// ["default", "sales", "analytics", "information_schema"]
```

## tables

Lists all base tables in a catalog and schema.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const tables = await client.tables({ catalog: "hive", schema: "sales" })
// ["orders", "customers", "products", "invoices"]
```

## views

Lists all views in a catalog and schema.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const views = await client.views({ catalog: "hive", schema: "sales" })
// ["monthly_revenue", "top_customers"]
```

## columns

Lists all columns for a specific table, including their types and metadata.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const columns = await client.columns({
  catalog: "hive",
  schema: "sales",
  table: "orders",
})
// [
//   ["id", "varchar", "", "Order identifier"],
//   ["amount", "double", "", "Total order amount"],
//   ["created_at", "timestamp(3)", "", "When the order was placed"],
// ]
```

### Typed objects with `asObject`

Pass `asObject: true` to get `ColumnInfo[]` objects instead of raw tuples:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const columns = await client.columns({
  catalog: "hive",
  schema: "sales",
  table: "orders",
  asObject: true,
})
// [
//   { name: "id", type: "varchar", extra: "", description: "Order identifier" },
//   { name: "amount", type: "double", extra: "", description: "Total order amount" },
// ]

for (const col of columns) {
  console.log(`${col.name}: ${col.type}`)
}
```

## Full Discovery Example

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "bearer", token: "eyJhbGciOiJSUzI1NiIs..." },
  catalog: "iceberg",
})

// Discover all tables across all schemas
const schemas = await client.schemas({ catalog: "iceberg" })

for (const schema of schemas) {
  if (schema === "information_schema") {
    continue
  }

  const tables = await client.tables({ catalog: "iceberg", schema })
  console.log(`${schema}: ${tables.join(", ")}`)

  for (const table of tables) {
    const columns = await client.columns({ catalog: "iceberg", schema, table })
    console.log(
      `  ${table}: ${columns.map(([name, type]) => `${name} (${type})`).join(", ")}`
    )
  }
}
```

keywords: schemas tables views columns inspecting


docId: trino-client/overview/introduction

slug: overview/introduction

title: Introduction

text: What is the Trino Client?

text: Core Capabilities

text: Quick Example

text: How It Works

content:
---
title: Introduction
description: An HTTP client for executing queries and inspecting metadata on Trino clusters.
---

## What is the Trino Client?

The `@lakeql/trino-client` package provides a typed HTTP client for communicating with a Trino cluster via its [REST API](https://trino.io/docs/current/develop/client-protocol.html). It handles authentication, paginated result fetching, query cancellation, and catalog metadata inspection.

Built on native `fetch` with zero runtime dependencies. Supports basic and bearer token authentication, automatic pagination through `nextUri` links, configurable retry with exponential backoff, and an async-generator streaming mode for memory-efficient processing of large result sets.

## Core Capabilities

- **Query execution** — Send SQL statements and collect all result pages into a single array
- **Streaming** — Yield rows one at a time via an async generator for large datasets
- **Row transforms** — Map raw row arrays to typed objects with a `transform` function
- **Query cancellation** — Cancel in-flight queries via `AbortSignal` or `cancelQuery()`
- **Retry with backoff** — Automatic retry on transient failures (429, 5xx, network errors)
- **Metadata inspection** — List schemas, tables, views, and columns for any catalog
- **Authentication** — Basic auth (username/password) and bearer token auth
- **User impersonation** — Execute queries on behalf of another user via the `X-Trino-User` header

## Quick Example

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "sales",
})

const rows = await client.query<[string, number]>({
  sql: "SELECT region, SUM(amount) FROM orders GROUP BY region",
})

console.log(rows)
// [["us-east", 42000], ["eu-west", 31500], ...]
```

## How It Works

1. The client sends a `POST` request to `/v1/statement` with the SQL body
2. Trino responds with an initial result (possibly empty) and a `nextUri`
3. The client follows `nextUri` links with `GET` requests until no more pages remain
4. All `data` arrays from each page are concatenated into the final result

This pagination is handled transparently — you call `query()` and get back the full result set.

keywords: client trino introduction executing queries


docId: trino-client/queries/executing-queries

slug: queries/executing-queries

title: Executing Queries

text: Basic Usage

text: Row Transforms

text: User Impersonation

text: Query Cancellation

text: Error Handling

text: How Pagination Works

text: QueryProps Reference

content:
---
title: Executing Queries
description: Run SQL statements against Trino and collect all result pages into a single array.
---

## Basic Usage

The `query` method executes a SQL statement and automatically follows Trino's `nextUri` pagination links until all result pages have been collected.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "sales",
})

const rows = await client.query<[string, string, number]>({
  sql: "SELECT id, region, amount FROM orders WHERE status = 'shipped'",
})

for (const [id, region, amount] of rows) {
  console.log(`Order ${id}: ${region} - $${amount}`)
}
```

## Row Transforms

Use the `transform` option to map raw row arrays into typed objects:

```ts
import { TrinoClient } from "@lakeql/trino-client"
import type { Column } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "sales",
})

interface Order {
  id: string
  region: string
  amount: number
}

const orders = await client.query<Order>({
  sql: "SELECT id, region, amount FROM orders",
  transform: (row: unknown[], columns: Column[]) => ({
    id: row[0] as string,
    region: row[1] as string,
    amount: row[2] as number,
  }),
})

// orders: Order[]
console.log(orders[0].region)
```

The `transform` function receives the raw row array and the column metadata, and returns the desired shape.

## User Impersonation

Pass `impersonateAs` to execute the query as a different Trino user. This sets the `X-Trino-User` header for that request only:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const rows = await client.query<[string]>({
  sql: "SELECT current_user",
  impersonateAs: "data-team-service",
})
// rows: [["data-team-service"]]
```

## Query Cancellation

Cancel a running query using an `AbortSignal`:

```ts
import { TrinoClient, TrinoCancellationError } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

const controller = new AbortController()

// Cancel after 10 seconds
setTimeout(() => controller.abort(), 10_000)

try {
  const rows = await client.query({
    sql: "SELECT * FROM very_large_table",
    signal: controller.signal,
  })
} catch (error) {
  if (error instanceof TrinoCancellationError) {
    console.log("Query was cancelled")
  }
}
```

You can also cancel queries by ID:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

// Cancel a specific query
await client.cancelQuery("20240101_123456_00001_abcde")

// Cancel all active queries
await client.cancelAllQueries()

// Check what's currently running
const active = client.getActiveQueries()
```

## Error Handling

The client throws typed errors depending on the failure:

```ts
import {
  TrinoClient,
  TrinoClientError,
  TrinoQueryError,
  TrinoCancellationError,
} from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
})

try {
  const rows = await client.query({ sql: "SELECT * FROM nonexistent_table" })
} catch (error) {
  if (error instanceof TrinoQueryError) {
    // Trino returned an error in the response body
    console.error(error.errorName) // e.g. "TABLE_NOT_FOUND"
    console.error(error.errorType) // e.g. "USER_ERROR"
    console.error(error.queryId)
  } else if (error instanceof TrinoClientError) {
    // HTTP-level error (non-2xx status)
    console.error(error.statusCode) // e.g. 503
    console.error(error.message)
  } else if (error instanceof TrinoCancellationError) {
    // Query was cancelled via AbortSignal
    console.log("Cancelled:", error.queryId)
  }
}
```

## How Pagination Works

1. A `POST` is sent to `/v1/statement` with the SQL body
2. Trino returns an initial response with (optionally) data and a `nextUri`
3. The client follows `nextUri` with `GET` requests, collecting `data` arrays
4. When no `nextUri` is returned, all pages have been fetched
5. The concatenated result array is returned

This is entirely transparent — you call `query()` and get the complete result regardless of how many pages Trino needed internally.

## QueryProps Reference

<InterfaceReference file="trino-client/src/types" name="QueryProps" />

keywords: executing queries statements against trino


docId: trino-client/queries/streaming

slug: queries/streaming

title: Streaming

text: Basic Usage

text: Streaming with Transforms

text: Cancelling a Stream

text: When to Use stream vs query

text: Memory Efficiency

content:
---
title: Streaming
description: Stream query results row-by-row using an async generator for memory-efficient processing.
---

## Basic Usage

The `stream` method executes a SQL statement and returns an async generator that yields rows one at a time as pages are fetched. Ideal for large result sets where holding all data in memory would be impractical.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "logs",
})

const stream = await client.stream<[string, string, number]>({
  sql: "SELECT timestamp, level, duration FROM request_logs",
})

for await (const [timestamp, level, duration] of stream) {
  if (duration > 5000) {
    console.warn(`Slow request at ${timestamp}: ${duration}ms`)
  }
}
```

## Streaming with Transforms

Combine streaming with `transform` to get typed objects:

```ts
import { TrinoClient } from "@lakeql/trino-client"
import type { Column } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "logs",
})

interface LogEntry {
  timestamp: string
  level: string
  duration: number
}

const stream = await client.stream<LogEntry>({
  sql: "SELECT timestamp, level, duration FROM request_logs",
  transform: (row: unknown[], columns: Column[]) => ({
    timestamp: row[0] as string,
    level: row[1] as string,
    duration: row[2] as number,
  }),
})

for await (const entry of stream) {
  if (entry.level === "ERROR") {
    console.error(`Error at ${entry.timestamp}: ${entry.duration}ms`)
  }
}
```

## Cancelling a Stream

Pass an `AbortSignal` to cancel a stream mid-flight:

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "logs",
})

const controller = new AbortController()

const stream = await client.stream({
  sql: "SELECT * FROM events",
  signal: controller.signal,
})

let count = 0
for await (const row of stream) {
  count += 1
  if (count >= 1000) {
    controller.abort()
    break
  }
}
```

## When to Use stream vs query

| Scenario                          | Method   |
| --------------------------------- | -------- |
| Result fits comfortably in memory | `query`  |
| Large or unbounded result sets    | `stream` |
| Need all rows before processing   | `query`  |
| Can process rows incrementally    | `stream` |
| ETL pipelines / file exports      | `stream` |

## Memory Efficiency

With `query`, all pages are collected into a single array before the promise resolves. With `stream`, each page is fetched on-demand and rows are yielded immediately — only one page of data is held in memory at a time.

```ts
import { TrinoClient } from "@lakeql/trino-client"

const client = new TrinoClient({
  host: "https://trino.example.com",
  port: 8443,
  auth: { type: "basic", username: "analyst", password: "secret" },
  catalog: "hive",
  schema: "analytics",
})

// Processing millions of rows without loading them all into memory
const stream = await client.stream<[string, number]>({
  sql: "SELECT user_id, event_count FROM daily_aggregates",
})

let processed = 0
for await (const [userId, count] of stream) {
  console.log(`${userId}: ${count}`)
  processed += 1
}

console.log(`Processed ${processed} rows`)
```

keywords: stream streaming query results row-by-row