# Connect

<Anatomy call="connect" shape="args" exported="db">
  <AnatomyPart slot="target" label="Target" code="url," mark="url">
    A connection string, a pool from `open`, or `{ primary, replicas }`. A string or a pool returns the client. A topology returns a promise.
  </AnatomyPart>
  <AnatomyPart slot="schema" label="Schema">
    <AnatomyLine code="{" />
    <AnatomyLine code="schema," mark="required" indent={2} />
    <AnatomyLine code="}," />
    The [schema](/docs/schema/the-schema) types the client. The other decisions are the pages below. [`close()`](#close) is on this page.
  </AnatomyPart>
</Anatomy>

Import `connect` from the [driver](/docs/operate/drivers) you installed. The process keeps one client. Use a TCP URL such as `postgres://localhost:5432/app`. A Windows named pipe is not a URL this version opens.

<Callout type="info" title="The schema">
The client is typed by the schema you pass. A `Register` augmentation, which `okm init` writes, feeds the `Row`, `Insert`, and `Update` helper types when no schema is passed.
</Callout>

## The declaration

The list is how often you reach for each part while opening a client. The target and the schema come first.

```ts title="db.ts"
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";

const notes = table("notes", {
  id: t.identity(),
  title: t.text(),
});

const app = schema({ tables: [notes] });

export const db = connect(process.env.DATABASE_URL!, { schema: app }); // [!code focus]
```

| Order | Page | You use it for |
| --- | --- | --- |
| 1 | [Drivers](/docs/operate/drivers) | The import. |
| 2 | [Target](/docs/operate/target) | A URL, a pool, or memory. |
| 3 | [Topology](/docs/operate/replicas-and-topology) | A primary and its replicas. |
| 4 | [Check](/docs/operate/startup-check) | The server, the floor, and the catalog hash. |
| 5 | [Session](/docs/operate/session-and-pool) | Pool size, TLS, search path, and deadlines. |
| 6 | [Session settings](/docs/operate/session-settings) | `sessionSettings()` and `db.with()` GUC values. |
| 7 | [Limits](/docs/operate/query-limits) | Defaults for `find`, `page`, `groupBy`, and includes. |
| 8 | [Errors](/docs/operate/errors) | HTTP statuses and row values. |
| 9 | [Generators](/docs/schema/keys-and-identity#id-generators) | `uuidv4`, `uuidv7`, and `okid`. |
| 10 | [Observability](/docs/operate/observability) | Observers and OpenTelemetry spans. |

## Close

A script calls `close()` when it is done. A server keeps the client for the life of the process. The call ends the pool only when this client opened it. Who opened it is [Target](/docs/operate/target).

| Client | `close()` |
| --- | --- |
| Opened the pool | Ends that pool. |
| Adopted a pool | Resolves. The pool stays open. |
| `using()` | Absent on that client. |

`await using` is that call at the end of the block. It calls the same `close()`. The client has `[Symbol.asyncDispose]` when the runtime defines that symbol. A runtime without the symbol leaves the client unchanged.

A finished script should call `close()` or use `await using`. Set `idleTimeoutMs: 0` only when a short script must exit without that call on a driver whose idle timer would otherwise keep the process alive.

```ts title="script.ts"
import { connect } from "okmodel/pg/postgresjs";
import { schema, table, t } from "okmodel/pg";

const notes = table("notes", {
  id: t.identity(),
  title: t.text(),
});

const app = schema({ tables: [notes] });

export async function read() {
  await using db = connect(process.env.DATABASE_URL!, { schema: app }); // [!code focus]
  await db.notes.find({ limit: 1 });
}
```

A second `close()` waits on the same close when this client opened the pool. The first call starts the close. A later call returns that promise. `for()` and `unscoped()` reuse it. An adopted pool resolves without closing it, on every call.

[`using()`](/docs/operate/replicas-and-topology) returns a client with no `close`. The root `close()` stops the probes and closes every pool that `connect` opened.

`close()` before the check settles, on a client that opened the pool, does not reject `connected` when the check succeeds. When the check fails, the rejection is `The client was closed before it connected. Await connected before close(), or do not close it before use.` That promise is [Check](/docs/operate/startup-check).

Index: [/llms.txt](/llms.txt)
