# Installation

> Add the core package, install its PostgreSQL schema, and check compatibility before a process starts.

Workhorse stores durable state in your database, so installing it is a schema change — and schema
changes deserve a deliberate deployment step, not a side effect of the first process to boot. This
page separates the two actions: installation, which creates database objects once, and the startup
check every runtime process should make instead.

## Requirements

Every SDK supports PostgreSQL 15 or newer without an extension. The shared schema CLI requires
Node.js 22 or newer during deployment, including when the application itself runs Python or Go.
Choose the runtime that matches your application:

- TypeScript requires Node.js 22 or newer and an ESM application.
- Python supports Python 3.10 or newer through synchronous or asynchronous drivers.
- Go requires Go 1.25 or newer and supports pgx or `database/sql`.

`installSchema` refuses an older PostgreSQL up front, naming the server's version, rather than
failing partway through with a syntax error that reads like a Workhorse bug.

## Add the package

Install the SDK. Each package includes its default PostgreSQL driver.

<Tabs items={["TypeScript", "Python", "Go"]}>
  <Tab value="TypeScript">

    ```bash
    npm install @stablemates/workhorse@0.1.0-beta.1
    ```

  </Tab>
  <Tab value="Python">

    ```bash
    pip install stablemates-workhorse==0.1.0b1
    ```

    Use the `asyncpg` extra when that is your application's driver instead of Psycopg.

  </Tab>
  <Tab value="Go">

    ```bash
    go get github.com/stablemates/workhorse/go@v0.1.0-beta.1
    ```

  </Tab>
</Tabs>

Add a database adapter (`@stablemates/workhorse-drizzle`, `@stablemates/workhorse-prisma`, `@stablemates/workhorse-typeorm`,
`@stablemates/workhorse-kysely`) or `@stablemates/workhorse-dashboard` only when that integration belongs in the same
process.

For TypeScript applications, `workhorse init` can scaffold the wiring. It inspects the project,
writes a worker configuration, and prints a dashboard mount — but it leaves your routes and package
manifest alone.

```bash
npx workhorse init
```

## Give Workhorse a database

Workhorse creates every object inside a schema named `workhorse`. The connecting role must be able
to create that schema plus its tables, indexes, partitions, and functions.

Your process supplies the connection through its normal configuration — typically a `pg` `Pool`
built from `DATABASE_URL`. The CLI reads `--database-url`, then `WORKHORSE_DATABASE_URL`, then
`DATABASE_URL`.

## Install the schema deliberately

When the target database is new, install from a deployment step. `schema status` then reports the
installed version against what the runtime expects.

```bash
npx --package @stablemates/workhorse workhorse schema install
npx --package @stablemates/workhorse workhorse schema migrate
npx --package @stablemates/workhorse workhorse schema status
npx --package @stablemates/workhorse workhorse schema status --json
```

Every command rejects unknown options and accepts both `--flag value` and `--flag=value`.
Command-specific help exits before the CLI connects to PostgreSQL.

TypeScript deployment code can call the same step as `installSchema`.

```ts
import { installSchema, Pool } from "@stablemates/workhorse";

const pool = new Pool({ connectionString: process.env.DATABASE_URL });
await installSchema(pool);
await pool.end();
```

`installSchema` targets a clean database. If a `workhorse` schema already exists, it proceeds only
when that schema carries exactly the current version and no legacy relations; anything mixed,
unversioned, or older is refused. It never treats installation as an upgrade path.

## Migrate an installed schema

Run `migrateSchema` from a deployment step before processes from the new release start. It applies
the package's immutable, forward-only migration steps in order.

```ts
import { migrateSchema } from "@stablemates/workhorse";

await migrateSchema(pool);
```

The migration refuses a missing schema, a version below its supported baseline, a newer version,
or a gap in the ordered plan. Each step commits one version in its own transaction behind an
advisory lock, and a failed step rolls back atomically, so a rerun resumes from the recorded
version. The same step is available from the CLI as `workhorse schema migrate`, and an
already-current schema is left unchanged. Development schemas at retired versions below the
baseline still require a reset.

## Check before a runtime starts

Application and worker processes should verify the schema, never install it. That split keeps the
destructive authority to create database objects out of every long-lived process.

```ts
import { assertSchemaCompatible } from "@stablemates/workhorse";

await assertSchemaCompatible(pool);
```

`assertSchemaCompatible` reads the installed version without creating or changing anything. If the
schema is missing, it says so and points at the installation step; if the version differs from the
runtime's, it names both numbers.

When you want the raw values instead of an assertion — for a health endpoint, for example — use
`readSchemaVersion` and compare against the exported `WORKHORSE_SCHEMA_VERSION` constant.

```ts
import { readSchemaVersion, WORKHORSE_SCHEMA_VERSION } from "@stablemates/workhorse";

const installed = await readSchemaVersion(pool); // number, or null when absent
console.log({ installed, expected: WORKHORSE_SCHEMA_VERSION });
```

For the server side of the same question, `readPostgresSupport` classifies the connected PostgreSQL
as supported and tested, supported but untested, or unsupported.

## Next

- [Quickstart](/docs/quickstart) — create a queue and run your first handler
- [Core concepts](/docs/concepts) — understand state, ownership, and delivery
- [Compatibility](/docs/compatibility) — the tested support boundary in detail

---

Exact schema requirements and installation boundaries:
[architecture reference](https://github.com/stablemates/workhorse/blob/main/docs/architecture.md#operational-limits).
