# Easy CMS 1.7: Postgres poolers, JSON logs, health checks and a Docker image

> What changed from Easy CMS 1.4 to 1.7: Postgres pool options and PgBouncer, JSON logs with request ids, health checks in every setup, an official Docker image, and a tested setup for several servers.

URL: https://easy-cms-website.vercel.app/blog/easy-cms-1-7  
Published: 2026-10-25  
Updated: 2026-10-26

Easy CMS 1.4 made background work run once however many servers share a database. Three releases since finish the job: everything a team needs to run Easy CMS on several servers behind a load balancer, and to know what it is doing there. None of them breaks anything, and none needs a migration.

## A setup that is tested, not assumed

The new [Reference architecture](/docs/deploy/production) page says what is supported when one server isn't enough: Postgres, S3-compatible storage for uploads, any number of identical instances behind a load balancer without sticky sessions, and a CDN in front. It also says plainly what is single-server only (SQLite on a disk, uploads on a disk) and what isn't supported (several regions, read replicas).

CI now checks this on every change. It starts two instances on one Postgres and one bucket behind a round-robin proxy, logs in on one and uses the session on the other, uploads through one and downloads through the other, counts failed logins across both, and runs scheduled publishing on both at once to check each post is published once.

## Postgres connection options (1.5)

`postgres()` takes `prepare`, `statementTimeoutMs`, `idleTimeoutMs`, `connectTimeoutMs` and `applicationName`. Connections show up as `easy-cms` in `pg_stat_activity`.

```ts
db: postgres({ url: process.env.DATABASE_POOLER_URL, max: 2, prepare: false })
```

On serverless hosts and with many instances, connect through a pooler. CI runs every Postgres test through PgBouncer in transaction mode. The [Databases](/docs/databases#connections) guide explains pool sizes, and when to turn off prepared statements.

Organisations that want the CMS kept apart from business data can give it a schema and a role of its own. The new [Database isolation](/docs/database-isolation) guide shows four levels, from a shared database to a server of its own, with the SQL to move an existing site.

## JSON logs and request ids (1.6)

```ts
logs: { format: 'json' }
```

Or set `EASY_CMS_LOG_FORMAT=json` on the host. Every line becomes one JSON object, with the time, level, message and the error's stack, ready for Datadog, Loki or CloudWatch. Every API response carries an `X-Request-Id` header, every line logged while answering it has the same id, and an id your load balancer sends is kept. With JSON logs each request also gets a line with its path, status and duration. See [Logs](/docs/deployment#logs).

## Health checks (1.7)

Every setup now answers two probes under the API:

- `/api/cms/healthz` answers `ok` while the process runs, without touching the database.
- `/api/cms/readyz` answers `200` when the database answers and no migration is pending, and `503` otherwise.

Point the load balancer, or Kubernetes' readiness probe, at `readyz`, and liveness at `healthz`. They answer even when the CMS can't start, and stay out of the request log. See [Health checks](/docs/deployment#health-checks).

## An official Docker image

`ghcr.io/maritonx/easy-cms` runs `easy-cms serve` with the SQLite and Postgres adapters, S3 storage and SMTP email. Add your config and migrations:

```dockerfile
FROM ghcr.io/maritonx/easy-cms:1
COPY easy-cms.config.ts ./
COPY easy-cms ./easy-cms
```

It runs as a non-root user, checks `/readyz`, and comes for amd64 and arm64. Each release builds it. See [Docker](/docs/deploy/docker#the-official-image).

## Also

- Logging out on a page with unsaved changes asks first, and staying keeps you logged in (1.4.3).
- Reads with `locale: 'all'` are typed as they return (1.4.2).

## Upgrading

Upgrade every package together. There is no migration:

```bash
npm install @easy-cms/core@latest easy-cms@latest
```

The [changelog](/changelog) lists every release.
