> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Использование Bun с ClickHouse Managed Postgres

> Подключение приложения на Bun к ClickHouse Managed Postgres с помощью встроенного клиента Bun.sql и TLS с проверкой сертификата

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Бета</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Возможность в статусе бета</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.guides-bun-beta" />

[Bun](https://bun.sh) — это среда выполнения JavaScript и TypeScript со встроенным клиентом Postgres `Bun.sql`, поэтому устанавливать отдельный драйвер не нужно.
В этом руководстве вы подключите Bun к ClickHouse Managed Postgres по TLS с проверкой сертификата, создадите таблицу, выполните запросы и транзакцию, а затем с помощью `Bun.serve` будете отдавать строки по HTTP.

<h2 id="prerequisites">
  Предварительные требования
</h2>

* [Bun](https://bun.sh/docs/installation) версии 1.4 или новее. Это руководство проверено на Bun 1.4.2 и Postgres 18.
* Аккаунт ClickHouse Cloud.
* [`psql`](https://www.postgresql.org/download/) для создания базы данных. Также можно выполнить оператор `CREATE DATABASE` в [консоли SQL](/ru/integrations/connectors/sql-clients/sql-console).

<h2 id="create-service">
  Создание сервиса ClickHouse Managed Postgres
</h2>

В консоли ClickHouse Cloud нажмите **New service** и выберите **Postgres**. Инстанс будет готов через несколько минут. Пошаговые инструкции приведены в [кратком руководстве по началу работы](/ru/products/managed-postgres/quickstart).

<h2 id="connection-details">
  Получите сведения о подключении
</h2>

Откройте свой сервис и нажмите **Подключение** на левой боковой панели. Оставьте выбранным вариант **Directly** и включите **Use SSL**. URL теперь будет заканчиваться на `sslmode=verify-full&sslrootcert=...`. Нажмите **Download CA certificate**, чтобы скачать CA‑сертификат для вашего инстанса.

В этом руководстве используется **прямое** подключение через порт `5432`. Приложение `Bun.serve` работает как долгоживущий процесс, а `Bun.sql` поддерживает собственный пул соединений, поэтому пулер на стороне сервера не требуется. Если вы запускаете много кратковременных процессов Bun, см. раздел [Подключение через PgBouncer](#pgbouncer).

<h2 id="setup">
  Настройка проекта
</h2>

Создайте проект:

```bash theme={null}
mkdir bun-postgres && cd bun-postgres
bun init -y
```

<Tip>
  **Добавляете в существующее приложение?**

  Пропустите `mkdir` и `bun init -y`: `Bun.sql` встроен в Bun, поэтому устанавливать ничего не нужно. В корне проекта перейдите к разделу [Настройка соединения](#configure), а также добавьте `NODE_EXTRA_CA_CERTS=./ca-certificate.pem` перед командой запуска вашего приложения, чтобы оно могло проверить сертификат сервера.
</Tip>

<h2 id="configure">
  Настройка соединения
</h2>

Переместите загруженный CA‑сертификат в проект и переименуйте его в `ca-certificate.pem`:

```bash theme={null}
mv ~/Downloads/<service-name>-ca-certificate.pem ca-certificate.pem
```

Создайте базу данных для приложения. Замените `<PASSWORD>` и хост значениями из модального окна **Подключение**:

```bash theme={null}
psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "CREATE DATABASE guide_bun;"
```

```text theme={null}
CREATE DATABASE
```

Добавьте URL подключения к базе данных `guide_bun` в файл `.env` (если файла нет, создайте его). Bun автоматически загружает `.env`, а экспорт `sql` из `bun` считывает переменную `DATABASE_URL`:

```bash title=".env" theme={null}
DATABASE_URL=postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/guide_bun?sslmode=verify-full
```

Если пароль содержит специальные символы, закодируйте его для URL (URL-encoding). Не добавляйте `.env` в систему контроля версий.

Добавьте эти скрипты в `package.json`; если блок `scripts` уже существует, объедините их с ним. Эти скрипты передают CA‑сертификат в Bun через `NODE_EXTRA_CA_CERTS`:

```json title="package.json" theme={null}
"scripts": {
  "setup": "NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run setup.ts",
  "queries": "NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run queries.ts",
  "serve": "NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run server.ts"
}
```

<Note>
  **Как Bun проверяет сертификат сервера**

  * `sslmode=verify-full` заставляет `Bun.sql` проверять и цепочку сертификатов, и имя хоста.
  * Не копируйте параметр `sslrootcert` из URL в консоли. `Bun.sql` не обрабатывает его, а передаёт серверу как параметр времени выполнения, и соединение завершается ошибкой `unrecognized configuration parameter "sslrootcert"`.
  * Переменная `NODE_EXTRA_CA_CERTS` должна быть задана в окружении до запуска Bun. Bun не считывает её из `.env`, поэтому она задаётся в скриптах.
  * В Bun 1.4.2 передача скачанного сертификата через параметр `tls: { ca }` в `SQL` завершается ошибкой `certificate signature failure`. Используйте вместо этого `NODE_EXTRA_CA_CERTS`.
</Note>

<h2 id="create-table">
  Создание таблицы
</h2>

Создайте файл `setup.ts`. Он выводит состояние TLS для текущего сеанса и создаёт таблицу `todos`:

```ts title="setup.ts" theme={null}
import { sql } from "bun";

const [tls] = await sql`SELECT ssl, version FROM pg_stat_ssl WHERE pid = pg_backend_pid()`;
console.log("TLS:", tls);

await sql`
  CREATE TABLE IF NOT EXISTS todos (
    id         integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    title      text NOT NULL,
    done       boolean NOT NULL DEFAULT false,
    created_at timestamptz NOT NULL DEFAULT now()
  )
`;
console.log("Table todos is ready");

await sql.close();
```

Выполните его:

```bash theme={null}
bun run setup
```

```text theme={null}
$ NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run setup.ts
TLS: {
  ssl: true,
  version: "TLSv1.3",
}
Table todos is ready
```

Чтобы убедиться, что сертификат действительно проверяется, запустите файл без CA‑сертификата. Соединение будет отклонено:

```bash theme={null}
bun run setup.ts
```

```text theme={null}
error: unable to verify the first certificate
 errno: 0,
  code: "UNABLE_TO_VERIFY_LEAF_SIGNATURE"
```

<h2 id="query">
  Выполнение запросов к базе данных
</h2>

`Bun.sql` использует тегированные шаблонные строки. Каждое подставляемое значение передаётся как параметр привязки, поэтому пользовательский ввод можно передавать безопасно. Создайте файл `queries.ts`:

```ts title="queries.ts" theme={null}
import { sql } from "bun";

// Interpolated values are sent as bind parameters, never spliced into the SQL text
const title = "Download the CA certificate";
const [first] = await sql`INSERT INTO todos (title, done) VALUES (${title}, true) RETURNING *`;
console.log("Inserted:", first);

// Insert several rows at once with the sql(array) helper
const rows = [{ title: "Connect with Bun.sql" }, { title: "Serve rows with Bun.serve" }];
await sql`INSERT INTO todos ${sql(rows)}`;

// Both statements commit together, or neither does
await sql.begin(async (tx) => {
  const [todo] = await tx`INSERT INTO todos (title) VALUES ('Write a transaction') RETURNING id`;
  await tx`UPDATE todos SET done = true WHERE id = ${todo.id}`;
});

const open = await sql`SELECT id, title FROM todos WHERE done = ${false} ORDER BY id`;
console.log("Open todos:", open);

await sql.close();
```

`sql.begin` выполняет callback-функцию в рамках транзакции. Если callback-функция завершается успешно, транзакция фиксируется (коммит), а если она выбрасывает исключение — откатывается.

Запустите пример:

```bash theme={null}
bun run queries
```

```text theme={null}
$ NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run queries.ts
Inserted: {
  id: 1,
  title: "Download the CA certificate",
  done: true,
  created_at: 2026-09-30T16:51:23.040Z,
}
Open todos: [
  {
    id: 2,
    title: "Connect with Bun.sql",
  }, {
    id: 3,
    title: "Serve rows with Bun.serve",
  }, count: 2, command: "SELECT", lastInsertRowid: null,
  affectedRows: null
]
```

<h2 id="serve">
  Отдача строк по HTTP
</h2>

Создайте файл `server.ts` с конечной точкой `/todos`, которая возвращает список строк и создаёт новые:

```ts title="server.ts" theme={null}
import { sql } from "bun";

const server = Bun.serve({
  port: 3106,
  routes: {
    "/todos": {
      GET: async () => {
        const todos = await sql`SELECT id, title, done, created_at FROM todos ORDER BY id`;
        return Response.json(todos);
      },
      POST: async (req) => {
        const { title } = await req.json();
        const [todo] = await sql`INSERT INTO todos (title) VALUES (${title}) RETURNING *`;
        return Response.json(todo, { status: 201 });
      },
    },
  },
});

console.log(`Listening on ${server.url}`);
```

Запустите сервер:

```bash theme={null}
bun run serve
```

```text theme={null}
$ NODE_EXTRA_CA_CERTS=./ca-certificate.pem bun run server.ts
Listening on http://localhost:3106/
```

В другом терминале добавьте строку:

```bash theme={null}
curl -X POST http://localhost:3106/todos -H 'Content-Type: application/json' -d '{"title": "Take a screenshot"}'
```

```json theme={null}
{"id":5,"title":"Take a screenshot","done":false,"created_at":"2026-09-30T16:51:30.372Z"}
```

<h2 id="verify">
  Проверка
</h2>

Откройте [http://localhost:3106/todos](http://localhost:3106/todos) в браузере, чтобы увидеть все строки. Ответ будет выглядеть примерно так (отформатирован для удобства чтения):

```json theme={null}
[
  {"id":1,"title":"Download the CA certificate","done":true,"created_at":"2026-09-30T16:51:23.040Z"},
  {"id":2,"title":"Connect with Bun.sql","done":false,"created_at":"2026-09-30T16:51:23.136Z"},
  {"id":3,"title":"Serve rows with Bun.serve","done":false,"created_at":"2026-09-30T16:51:23.136Z"},
  {"id":4,"title":"Write a transaction","done":true,"created_at":"2026-09-30T16:51:23.184Z"},
  {"id":5,"title":"Take a screenshot","done":false,"created_at":"2026-09-30T16:51:30.372Z"}
]
```

В консоли откройте **консоль SQL** и последовательно разверните **guide\_bun**, **public** и **todos** — вы увидите те же строки:

| id | title | done | created\_at |
| - | - | - | - |
| 1 | Download the CA certificate | true | 2026-09-30 16:51:23.04083+00 |
| 2 | Connect with Bun.sql | false | 2026-09-30 16:51:23.136975+00 |
| 3 | Serve rows with Bun.serve | false | 2026-09-30 16:51:23.136975+00 |
| 4 | Write a transaction | true | 2026-09-30 16:51:23.184716+00 |
| 5 | Take a screenshot | false | 2026-09-30 16:51:30.372292+00 |

<h2 id="pgbouncer">
  Подключение через PgBouncer
</h2>

Если вы запускаете много кратковременных процессов Bun, лучше подключаться через встроенный [PgBouncer](/ru/products/managed-postgres/connection#pgbouncer). Выберите **via PgBouncer** в модальном окне **Подключение** и замените порт в `DATABASE_URL` на `6432`. CA‑сертификат и `sslmode=verify-full` остаются без изменений.

PgBouncer работает в режиме пулинга на уровне транзакций. `Bun.sql` по умолчанию использует именованные подготовленные операторы, и в наших тестах они работали через PgBouncer без ошибок. Если возникают ошибки `prepared statement does not exist`, создайте клиент с параметром `prepare: false`:

```ts theme={null}
import { SQL } from "bun";

const sql = new SQL(process.env.DATABASE_URL!, { prepare: false });
```

Передавайте `prepare` как параметр подключения, а не в URL. Как и в случае с `sslrootcert`, параметр URL `prepare=false` пересылается на сервер, и тот его отклоняет.

<h2 id="next-steps">
  Дальнейшие шаги
</h2>

* [Подключение](/ru/products/managed-postgres/connection): строки подключения, PgBouncer и TLS
* [Настройки](/ru/products/managed-postgres/settings): изменение параметров Postgres и PgBouncer
* [Реплики для чтения](/ru/products/managed-postgres/read-replicas): масштабирование нагрузки на чтение
* [Документация Bun SQL](https://bun.sh/docs/runtime/sql): полное описание API `Bun.sql`
