Build features

Database

Every app gets its own PostgreSQL database that no other app can see.

Each app has its own PostgreSQL schema and its own database role. The role can only see its own schema, so an app can never read another app's tables, even in the same workspace. There is nothing to set up: the database is created on the app's first deploy.

Create tables with migrations

Put SQL files in a migrations/ (or db/migrations/) folder. Name them so they sort in order:

my-app/
├── migrations/
│   ├── 0001_init.sql
│   └── 0002_add_region.sql
└── worker.ts
migrations/0001_init.sql
create table leads (
  id          bigint generated always as identity primary key,
  name        text not null,
  email       text,
  stage       text not null default 'new',
  created_by  text not null,
  created_at  timestamptz not null default now()
);

On each deploy, Inhaus runs only the migrations it has not run before, in name order. They run as the app's own role, in the app's schema, so table names need no prefix. If one fails, the deploy fails with migration_failed and the previous version stays live.

Reading and writing from your app

env.INHAUS_DB_SCHEMA holds the name of the app's schema.

Query from your AI tool

Your AI tool can read and change the data directly with db_query. Good for checking what is stored, fixing a bad row, or loading data.

How many leads are in the lead tracker, by stage?
Mark every lead from acme-old.com as "lost". Show me which rows first.
  • Each call runs one SQL statement. Pass values as parameters ($1, $2), never by pasting them into the SQL.
  • read mode runs in a read-only transaction.
  • write mode changes data and is recorded in the access log. Your AI tool should ask you before using it.
  • Editors and the Owner can use both modes.

The Data tab

The app's Data tab in the dashboard shows the database size and every table with its row count.

Limits

Limit
Rows returned by one db_query call1,000
Time per statement from db_query10 seconds