Dynamic tables
Create app-private tables, CRUD rows, and read/write them through the Data API — no separate database needed.
Dynamic tables are an app-private data store. Without attaching an external database, you can create tables and add, read, update, and delete rows. AxHub manages them in a PostgreSQL schema isolated per app.
Create a table
Create one from the CLI by specifying columns. The command defaults to a dry-run, so add --execute to actually create it.
axhub tables create orders --app demo \
--column 'title:text' \
--column 'qty:int' \
--column 'done:bool' \
--executeA column is name:type[:nullable][:default]. There are eight types:
| Type | Description |
|---|---|
text | String |
int · bigint | Integers |
float | Floating point |
bool | True/false |
timestamptz | Timestamp with timezone |
uuid | UUID |
jsonb | JSON |
With many columns, you can pass a schema file with --schema table.yaml. To track which user owns a row, set --owner-column <column>.
Work with rows
Add, read, update, and delete rows from the CLI too. Inserts, updates, and deletes need --execute.
axhub data insert orders --app demo --body '{"title":"First order","qty":2}' --execute
axhub data list orders --app demo
axhub data get orders <row-id> --app demo
axhub data count orders --app demo
axhub data update orders <row-id> --app demo --body '{"done":true}' --execute
axhub data delete orders <row-id> --app demo --executeTo insert many rows at once, use --batch rows.jsonl (one JSON object per line).
The Data API
There are two ways to work with table data from code.
① Inside an app — the SDK (recommended) · simplest, as the logged-in user. See Call the backend with the SDK.
const app = await makeApp(); // template-provided helper
const todos = await app.data.discover<{ id: string; title: string; done: boolean }>('todos');
await todos.list({ limit: 20 });
await todos.insert({ title: 'A task', done: false });② Externally — HTTP API + PAT · for agents, CI, or server-to-server calls from outside the app, use HTTP directly. The path is /data/{tenant}/{app}/{table}.
| Method · path | What it does |
|---|---|
GET /data/{tenant}/{app}/{table} | List |
GET …/{table}/_count | Count |
GET …/{table}/{id} | Get one |
POST …/{table} | Insert |
PATCH …/{table}/{id} | Update |
DELETE …/{table}/{id} | Delete |
const base = `https://api.axhub.ai/data/${tenant}/${app}/orders`;
const headers = { 'X-Api-Key': process.env.AXHUB_API_KEY, 'Content-Type': 'application/json' };
const rows = await fetch(base, { headers }).then((r) => r.json()); // list
await fetch(base, { method: 'POST', headers, body: JSON.stringify({ title: 'First order', qty: 2 }) }); // insertA PAT (personal access token) is sent in the X-Api-Key header. Don't hard-code it — keep it as a runtime secret in environment variables and read it on the server. Creating and managing tables (DDL) uses login (OAuth), not a PAT.
Share with another app
By default only the app that created a table can access it. To open read/write to another app or principal, grant a table grant.
axhub tables grants list --app demoSee the Data API for the exact endpoints, queries, grants, and auth.