# Features

Source: https://dabadata.com/docs/features/ (HTML) - https://dabadata.com/docs/features/index.md (this page as markdown)

dabadata (https://dabadata.com) hosts whole apps for people and their AI agents. Underneath is plain Postgres; you declare your tables and their access rules as one JSON definition, every allow or deny comes back with a sentence explaining it, every read and write is recorded in a trace, and changes stream live to every subscriber allowed to see them. Around that it hosts sign-in for your app's users (email, links, Google, Apple and more), file storage, your app's frontend at `<name>.dabadata.site` or your own domain, and an MCP server per project, so coding agents can build the app and people can use it inside ChatGPT and Claude with live widgets. This page lists every feature that exists today, grouped, each with a link to the page that documents it; what is not built yet is listed at the end.

## Data and schema

Tables, columns and constraints are declared in one definition and kept as plain Postgres tables; applying a definition only ever adds, with a dry run, versions and rollback.

- **[Plain Postgres underneath](https://dabadata.com/docs/index.md)** - your rows sit in ordinary Postgres tables, in a schema per environment, that any SQL tool can open.
- **[One declared definition](https://dabadata.com/docs/tables/index.md#hosted)** - roles, tables, columns and rules as one JSON document, applied with `PUT /v1/schema` (or a TypeScript file on a self-hosted server). It is plain data with no functions in it.
- **[Column types](https://dabadata.com/docs/tables/index.md#column-types)** - `text`, `int`, `float`, `bool`, `date`, `datetime`, `json`, `userId` (filled with the caller's id on insert) and `ref` (the id of a row in another table). Every value is checked against its type on every write and filter.
- **[Column options](https://dabadata.com/docs/tables/index.md#options)** - `optional`, `default` and `unique`; a column without either of the first two is required.
- **[Constraints](https://dabadata.com/docs/tables/index.md#constraints)** - unique columns, composite unique sets and named checks such as `stock >= 0`, kept by Postgres so they hold for every client at once. A write that breaks one is a 409 naming it.
- **[Ref deletes](https://dabadata.com/docs/tables/index.md#ref-deletes)** - `onDelete` on a `ref` column: `restrict`, `cascade` or `setNull`, done in the same transaction as the delete, each affected row traced.
- **[Implicit columns](https://dabadata.com/docs/tables/index.md#implicit-columns)** - every row gets `id`, `created_at`, `updated_at` and `created_by`, plus a `_seq` number that grows with every write, for catching up.
- **[Additive migrations and drift](https://dabadata.com/docs/tables/index.md#reload)** - applying creates missing tables and columns and never drops or retypes anything; what is in the database but not in the definition is reported as drift. Dropping a table is a separate, explicit call with a dry run.
- **[Dry run](https://dabadata.com/docs/tables/index.md#hosted)** - `dryRun: true` answers the plan (`create table x`, `add column x.y`) and changes nothing. A broken definition is refused as a whole with one message per problem, and unknown keys are refused so a typo cannot weaken a rule.
- **[Versions and rollback](https://dabadata.com/docs/api/index.md#schema-versions)** - every applied definition is stored as a version; rolling back applies an earlier one again as a new version.
- **[Live and test environments](https://dabadata.com/docs/projects/index.md#environments)** - every project has two environments that share nothing but the project: their own tables, definition, keys, users, trace and subscriptions.
- **[Export](https://dabadata.com/docs/projects/index.md#export)** - `GET /v1/project/export` streams every row of every table as NDJSON; the console also exports a table as CSV.

## Rules and access

One rule per operation per table, written as data, with row conditions, time, column rules, relations, actions (which may call Claude, OpenAI or Gemini with your key) and strict tables; every decision comes with a sentence that explains it.

- **[Rules per operation](https://dabadata.com/docs/rules/index.md#one-rule-per-op)** - each table has a `read`, `create`, `update` and `delete` rule. `read` must be explicit; a missing write rule means nobody.
- **[Rule grammar](https://dabadata.com/docs/rules/index.md#grammar)** - `anyone`, `authenticated`, `nobody`, `{ role }`, `{ owner }`, combined with `any` and `all`. Rules read like membership: "admins and editors may create, the owner may update".
- **[Row conditions](https://dabadata.com/docs/rules/index.md#row-conditions)** - `{ where: "status = 'published' or author = $user.id" }`: decide on the row's values, the caller and the time.
- **[Time-based visibility](https://dabadata.com/docs/rules/index.md#time)** - conditions on `$now` and `$today` make rows appear and disappear at their instant, also for live subscribers, with no write.
- **[Read rules as a row filter](https://dabadata.com/docs/rules/index.md#read-filters)** - a read rule is compiled into one SQL condition, so a list is exact at any table size and the caller only ever loads rows they may see.
- **[Explanations](https://dabadata.com/docs/rules/index.md#explanations)** - every decision is `allowed`, `denied` or `bypass` with one sentence naming the path through the rule; a denial carries that `explanation` and a `traceId`.
- **[Simulator](https://dabadata.com/docs/rules/index.md#simulator)** - `POST /v1/simulate` and the console's Rules page answer "would this person be allowed?", at any instant you choose, without changing anything.
- **[Column rules](https://dabadata.com/docs/rules/index.md#column-rules)** - narrow the update rule per column and limit a column to certain operators (for example: only `$inc`).
- **[Column read rules](https://dabadata.com/docs/rules/index.md#column-read-rules)** - hide a column's value from some callers (an owner-only field, admin notes, a value revealed at a time); a caller it denies gets the row without that key.
- **[Relations](https://dabadata.com/docs/rules/index.md#relations)** - a `via` rule grants access through another table, such as team membership.
- **[Actions](https://dabadata.com/docs/rules/index.md#actions-protecting-counters-capacity-and-stock)** - declared transactions that clients call by name with parameters; the steps run with the server's rights behind the action's own `allow` rule. The safe way to change counters, capacity and stock.
- **[AI calls in actions](https://dabadata.com/docs/ai/index.md)** - an action can end with one call to Claude (Anthropic), OpenAI or Gemini (Google), optionally with web search and cited sources, with your API key kept as an encrypted project secret and never sent anywhere but the provider. The definition fixes the model, the prompts and the token budget; clients send only params; the answer comes back in the response or is written into a row live. Limits per caller and per action, traced as `op: "ai"`, no server of your own.
- **[Strict tables](https://dabadata.com/docs/rules/index.md#strict-tables)** - `access: "views"`: end users read a table only through views and write it only through actions. Strict and open tables mix in one project.
- **[Access patterns](https://dabadata.com/docs/access-patterns/index.md)** - ten worked examples: predictions revealed at kick-off, drafts, scheduled content, secret columns, teams, per-role shapes, a leaderboard, a mixed project, counters.

## Views and joins

Declared, read-only views give each role its own shape of a table, with params, computed fields and joined rows, over HTTP, the client, live subscriptions and MCP.

- **[Declared views](https://dabadata.com/docs/views/index.md)** - a named, read-only shape of a table: which rows, which columns, computed boolean fields, params the caller fills in, and a different shape per role. Read with the server's rights; column read rules still apply.
- **[Joins](https://dabadata.com/docs/views/index.md#joins)** - nest one row of another table into each row (an answer with its question, an order line with its product): inner joins, one hop, up to four per view, in one SQL query, and live.
- **[Everywhere a table is](https://dabadata.com/docs/views/index.md#routes)** - `GET /v1/views/<name>`, `db.view()`, a live subscription to a view, and one MCP tool per view (`view_<name>`).

## Live data

Live subscriptions keep queries and views up to date over one socket, shaped for each subscriber by the same rules, including changes that happen by time.

- **[Live subscriptions](https://dabadata.com/docs/live/index.md)** - one WebSocket carries all of a client's subscriptions; the server sends the matching rows, then every change the subscriber is allowed to see.
- **[Shaped per subscriber](https://dabadata.com/docs/live/index.md#shaping)** - each subscriber gets rows filtered by their read rule and without the columns they may not read.
- **[Changes without a write](https://dabadata.com/docs/live/index.md#time)** - rows and columns that enter or leave by time (`$now`) arrive within about a second of the instant.
- **[View subscriptions](https://dabadata.com/docs/live/index.md#views)** - subscribe to a declared view, joined rows included.
- **[Catching up](https://dabadata.com/docs/protocol/index.md#reading)** - `?since=<seq>` answers only what changed after a cursor; the client reconnects with back-off and resubscribes by itself.
- **[Realtime tier](https://dabadata.com/docs/protocol/index.md#centrifugo)** - on the hosted service, live data is delivered through Centrifugo, with recovery after short disconnects.
- **[Presence and ephemeral messages](https://dabadata.com/docs/client/index.md#realtime-extras)** - `db.presence(table)` lists who is looking at a table now; `db.publish` / `db.onMessage` send typing indicators, cursors and the like. On the hosted realtime tier.

## Safe concurrent writes

Atomic operators, conditional writes, serializable transactions, constraints and actions make the safe write the short one, so concurrent users never lose updates.

- **[Atomic operators](https://dabadata.com/docs/concurrency/index.md#operators)** - `$inc`, `$dec`, `$min`, `$max`, `$append`, `$remove` (and `$set`), computed inside the UPDATE.
- **[Conditional writes](https://dabadata.com/docs/concurrency/index.md#expect)** - `expect` (write only if the row still holds what you read), `ifAbsent` (insert only if no such row exists) and `db.updateWithRetry`.
- **[Transactions](https://dabadata.com/docs/concurrency/index.md#transact)** - up to 50 writes and checks in one SERIALIZABLE Postgres transaction, all or nothing, retried on conflict; later ops can refer to rows inserted by earlier ones.
- **[Measured](https://dabadata.com/docs/concurrency/index.md#measured)** - a load script with hundreds of concurrent shoppers shows the naive and the safe way side by side.

## Sign-in for your app's users

Hosted accounts with email, sign-in links and social providers, or your own identity provider's JWTs, or tokens your backend mints, or anonymous access; all of them reach the same rules.

- **[Hosted accounts](https://dabadata.com/docs/end-user-auth/index.md)** - sign up with email and password, sign-in links by mail and password resets, per environment, with no backend of your own. Turned on with `auth.users`.
- **[Hosted pages or your own forms](https://dabadata.com/docs/end-user-auth/index.md#hosted-pages)** - ready sign-in pages titled with your project's name, or `db.auth` in the JavaScript client for your own UI; redirect URLs and app mode for links in mails.
- **[Social sign-in](https://dabadata.com/docs/sign-in-providers/index.md)** - Google, Apple, Microsoft, GitHub, GitLab, Discord, LinkedIn and Slack through your own OAuth apps, so the provider's screens show your app's name. Accounts link by verified email.
- **[Native apps](https://dabadata.com/docs/sign-in-providers/index.md#native)** - hand a Google or Apple ID token from a native app or your own sign-in button to dabadata and get a dabadata token pair back.
- **[Your own identity provider](https://dabadata.com/docs/identity/index.md#providers)** - trust JWTs from Clerk, Auth0, Firebase Auth, Supabase Auth, Google, Apple or your own issuer (`auth.issuers`), as they are or exchanged once for a dabadata token pair.
- **[Tokens minted by your backend](https://dabadata.com/docs/identity/index.md#user-tokens)** - `POST /v1/users/token` with the secret key: an access token for an hour and a refresh token for 30 days. Revoke a user everywhere with one call.
- **[Anonymous callers](https://dabadata.com/docs/identity/index.md#callers)** - no token at all: the caller may do what the rules allow `anyone`.
- **[Invites from your app](https://dabadata.com/docs/end-user-auth/index.md#invites)** - your signed-in users invite others, with roles you allow, from the browser.
- **[App admins](https://dabadata.com/docs/end-user-auth/index.md#app-admins)** - an admin page in your app can list users, change roles and names, and disable or remove them, under a rule you declare.
- **[Profiles](https://dabadata.com/docs/end-user-auth/index.md#profiles)** - a `users` table your rules can read, for names next to comments and attendee lists.
- **[A row for every new user](https://dabadata.com/docs/end-user-auth/index.md#on-signup)** - `onSignUp` inserts a row (a points balance, settings) with values the client cannot fake.
- **[Managing users](https://dabadata.com/docs/end-user-auth/index.md#managing)** - search, add, change roles, disable and delete in the console's Users page or with the secret key.

## File storage

Buckets of files for your app's users with the same rules, trace and live updates as rows, uploaded straight to object storage.

- **[Buckets with rules](https://dabadata.com/docs/storage/index.md#buckets)** - `read`, `write` and `delete` rules per bucket in the rule grammar of tables, with a size limit and allowed types.
- **[Direct uploads](https://dabadata.com/docs/storage/index.md#uploads)** - the client uploads straight to object storage (Cloudflare R2) with a short-lived signed URL; the bytes never pass through the API server.
- **[Downloads](https://dabadata.com/docs/storage/index.md#downloads)** - a signed URL valid 5 minutes after the read rule passes; files in a bucket readable by `anyone` also have a stable public URL.
- **[Files are rows](https://dabadata.com/docs/storage/index.md#buckets)** - every bucket is also a read-only table, `files_<bucket>`, that you can query, filter and subscribe to live.
- **[Client API](https://dabadata.com/docs/storage/index.md#client)** - `db.storage.upload`, `url`, `signedUrl`, `list` and `remove`, and a Files page in the console.

## Sites

Host your app's static frontend next to its data at `<name>.dabadata.site`, or your own domain from Starter, deployed by the CLI, the console or an AI agent.

- **[Static sites](https://dabadata.com/docs/sites/index.md)** - a plain HTML page or the build output of Vite, React, Vue, Svelte or Solid, served from the edge at `https://<name>.dabadata.site` on every plan. Serving does not count toward egress or requests.
- **[Deploy in one command](https://dabadata.com/docs/sites/index.md#deploy)** - `dabadata sites deploy ./dist --site my-app`; the site's address is added to the environment's allowed origins for you.
- **[Deploy from an AI agent](https://dabadata.com/docs/sites/index.md#agents)** - the MCP tool `site_deploy` takes the files and puts them live in one call.
- **[Readiness](https://dabadata.com/docs/sites/index.md#readiness)** - after a deploy, each public hostname is checked (DNS, TLS, route, the deploy it serves, the certificate), so a script or agent knows when the site is really live.
- **[Single-page apps](https://dabadata.com/docs/sites/index.md#spa)** - a fallback to `index.html` for client-side routing, or your own `404.html`.
- **[Rollback](https://dabadata.com/docs/sites/index.md#rollback)** - the newest 10 deploys are kept; putting an older one back is instant.
- **[Your own domain](https://dabadata.com/docs/sites/index.md#domains)** - from Starter, with an optional redirect partner (`example.com` to `www.example.com`).

## AI agents, MCP and apps in ChatGPT and Claude

Docs written for agents, a hosted MCP server per environment for coding agents (Claude Code, Cursor) and for people inside ChatGPT and Claude, live widgets, templates and a local stdio server.

- **[The agent kit](https://dabadata.com/docs/agents/index.md#one-link)** - `/llms.txt`, `/llms-medium.txt`, `/llms-full.txt`, every docs page as markdown at its `index.md`, and OpenAPI 3.1 at `/v1/openapi.json`.
- **[Hosted MCP server](https://dabadata.com/docs/mcp/index.md#hosted)** - every environment can be an MCP server at `/mcp/<project id>`, turned on with an `mcp` block in the definition.
- **[Developer tools](https://dabadata.com/docs/mcp/index.md#hosted-tools)** - with the secret key: `describe_app`, `get_definition`, `apply_definition` (with dry run), `trace_recent`, `simulate`, `sql_read`, widgets and sites tools, so a coding agent builds and debugs the app.
- **[App tools under the rules](https://dabadata.com/docs/mcp/index.md#credentials)** - a signed-in person gets one set of tools per table, `transact`, one tool per action and per view, every call held to the rules as that person and traced.
- **[Apps inside ChatGPT and Claude](https://dabadata.com/docs/agents/index.md#mcp)** - add the MCP address as a custom connector; people sign in on the project's own page (OAuth) and use the app in the chat.
- **[Live widgets](https://dabadata.com/docs/mcp/index.md#widgets)** - built-in `table`, `form` and `record` widgets drawn in the chat that update while people watch; custom widgets are one HTML document each.
- **[Templates](https://dabadata.com/docs/agents/index.md#templates)** - curated starting points (a definition with its rules, the `mcp` block and widgets) at `GET /v1/templates` and in the console.
- **[The prompt to paste](https://dabadata.com/docs/agents/index.md#prompt)** - a ready prompt for Claude Code, Cursor, Codex or any agent, and the one-line MCP setup (`claude mcp add ...`, `.cursor/mcp.json`).
- **[Local MCP server](https://dabadata.com/docs/mcp/index.md#local)** - a stdio MCP server for a self-hosted dabadata.

## Console, CLI and teams

A web console and a command-line tool for the people who build with dabadata, with workspaces, roles, invitations and an audit log.

- **[The console](https://dabadata.com/docs/console/index.md)** - at `/console/`: Overview, Definition (validate, diff, apply, versions, rollback), Tables (live rows, edit, CSV export), Files, SQL, Trace, Logs, Rules, Views, Apps, Users, Keys, Identity, Sites, Members, Usage and plan, Settings and a Playground.
- **[SQL console](https://dabadata.com/docs/console/index.md#sql)** - read-only by default; write mode previews the statements in a rolled-back transaction and commits only when you confirm. Saved queries.
- **[Keys and snippets](https://dabadata.com/docs/console/index.md#keys)** - rotate a key with 24 hours of overlap, revoke one at once, and copy ready code for plain HTML, Vite / React / Vue, Node, WordPress and curl.
- **[The `dabadata` CLI](https://dabadata.com/docs/getting-started/index.md#cli)** - sign in through the browser, then pull and push definitions, tail the trace, run SQL, set up MCP and deploy sites. A single file for macOS and Linux.
- **[Console accounts](https://dabadata.com/docs/accounts/index.md)** - sign in with email and password, an email link or Google; sessions you can see and revoke.
- **[Workspaces and roles](https://dabadata.com/docs/console/index.md#roles)** - workspaces hold projects; members are viewer, developer, admin or owner, the same in every project of the workspace.
- **[Invitations, transfer and audit log](https://dabadata.com/docs/accounts/index.md#invitations)** - invite by email, hand a workspace to another member, and read who changed what in the audit log.

## Trace, logs and debugging

Every mutation, read and subscription is recorded with who did it, the rule, the decision and why; request and realtime logs sit beside it.

- **[Trace](https://dabadata.com/docs/trace/index.md)** - one row per mutation, read and live subscription: who, which table, which rule, the decision, the explanation and how many subscribers received the change. Read it with `GET /v1/trace`, in the console or with the MCP tool `trace_recent`.
- **[Trace in the console](https://dabadata.com/docs/console/index.md#trace)** - live, filtered by user, table, operation, decision and time, with the before-and-after diff and "simulate as another user".
- **[Trace for your app's admins](https://dabadata.com/docs/trace/index.md#read-rule)** - a `trace.read` rule lets some of your own users read it, for a "recent activity" page.
- **[Logs](https://dabadata.com/docs/console/index.md#logs)** - API (every request), Realtime (sockets, subscriptions, fan-out) and Errors, live in the console and over `/v1/logs/...`.

## API, client and protocol

A JSON HTTP API under `/v1` with one WebSocket, a zero-dependency JavaScript client, OpenAPI 3.1, and a wire protocol written for SDK authors.

- **[HTTP API](https://dabadata.com/docs/api/index.md)** - a few dozen JSON endpoints under `/v1`, each documented with who may call it, the request, the answer and the errors; also as [OpenAPI 3.1](https://dabadata.com/v1/openapi.json).
- **[Queries](https://dabadata.com/docs/protocol/index.md#reading)** - filters with `$eq`, `$ne`, `$gt`, `$in`, `$like`, `$ilike`, `$contains` on json, `$and` / `$or`; sorting on up to 5 columns; up to 1,000 rows per read.
- **[Typed tables](https://dabadata.com/docs/client/index.md#typed-tables)** - `dabadata types` writes TypeScript types of your definition; `createClient<Database>()` then turns wrong table names, columns and value types into compile errors.
- **[JavaScript client](https://dabadata.com/docs/client/index.md)** - no dependencies, as an ES module or a script tag, with TypeScript types: insert, update, delete, query, subscribe, views, actions, transactions, storage and `db.auth`, refreshing tokens by itself.
- **[Wire protocol](https://dabadata.com/docs/protocol/index.md)** - everything a Dart, Swift or Kotlin SDK needs, with a conformance suite of more than 50 cases that checks any SDK against any server.
- **[Publishable and secret keys](https://dabadata.com/docs/projects/index.md#keys)** - a key pair per environment: the publishable key is safe in a browser, the secret key bypasses the rules and stays on a server.
- **[Restricted keys](https://dabadata.com/docs/projects/index.md#restricted)** - a key per backend job (a payment webhook, a cron job) that acts as one of your roles: rules and actions decide, the trace shows its name, it never bypasses anything.
- **[Outbound webhooks](https://dabadata.com/docs/webhooks/index.md)** - your own endpoint hears about row changes and action calls: Standard Webhooks signatures, retries for 15 hours, a delivery log with "send again", traced like every write. [Call dabadata from your backend](https://dabadata.com/docs/backend/index.md) shows the Vercel and Workers patterns.
- **[Scheduled actions](https://dabadata.com/docs/schedules/index.md)** - run one of your actions on a UTC cron (a nightly cleanup, a daily reset, a morning summary), as a role you name, traced like any call; no cron job of your own. Action steps can change [many rows at once](https://dabadata.com/docs/rules/index.md#bulk-steps) (`where: "created_at < $now - 30 days"`).
- **[Allowed origins](https://dabadata.com/docs/projects/index.md#cors)** - limit which web origins may call an environment.
- **[Project secrets](https://dabadata.com/docs/projects/index.md#secrets)** - values a definition needs but must not contain, such as an identity provider's shared signing key.

## WordPress plugin

A WordPress plugin connects a site to a project, maps WordPress users and roles to it, and puts live tables on pages.

- **[Connect in two clicks](https://dabadata.com/docs/wordpress/index.md#connect)** - from **Settings > dabadata**, to a new project made from the WordPress template or an existing one.
- **[WordPress users as project users](https://dabadata.com/docs/wordpress/index.md#identity-bridge)** - WordPress stays the login; every WordPress role, custom roles included, maps to a project role.
- **[Live table block and shortcode](https://dabadata.com/docs/wordpress/index.md#live-table)** - everyone sees rows change as they happen; logged-in visitors add and edit them under the project's rules.
- **[The mirror](https://dabadata.com/docs/wordpress/index.md#mirror)** - the site's own content changes stream into dabadata and show live in the WordPress admin.

## Self-hosting

Run the whole of dabadata on your own machine or server, over your own Postgres, with the same API as the hosted service.

- **[One command](https://dabadata.com/docs/self-hosting/index.md#quick-start)** - `docker compose up` starts Postgres 16 and the server on port 4600: the API, the viewer, the site, these docs and the live demo.
- **[Without Docker](https://dabadata.com/docs/self-hosting/index.md#without-docker)** - Bun and Postgres from a checkout of the repository.
- **[The default project](https://dabadata.com/docs/self-hosting/index.md#default-project)** - one project defined in a file with a single project key; the same server can also host many projects with live and test environments.
- **[The viewer](https://dabadata.com/docs/self-hosting/index.md#what-you-get)** - tables, trace and the rules simulator at `/`.
- **[No plan limits](https://dabadata.com/docs/limits/index.md#scope)** - a self-hosted server's own project has no plan and no limits. Sites need some Cloudflare setup of your own.

## Plans and limits

Plans are per workspace (Free, Starter, Pro, Scale, Enterprise), never per seat or per read; nothing is charged during the beta, and every limit is a hard cap unless the owner opts into overages.

- **[Plans and their limits](https://dabadata.com/docs/limits/index.md#plans)** - connections, database and file storage, egress, trace and log retention, requests per second, projects, team members, sites and custom domains, per plan. Prices are on the [pricing page](https://dabadata.com/pricing/).
- **[Free during the beta](https://dabadata.com/docs/billing/index.md#beta)** - plan changes take effect at once and cost nothing; Free and Starter are self-service.
- **[Billing when it is on](https://dabadata.com/docs/billing/index.md)** - Stripe checkout and customer portal per workspace; overages are opt-in, so usage is never billed beyond the plan's price by surprise.
- **[Clear answers at a limit](https://dabadata.com/docs/limits/index.md#at-the-limit)** - a machine-readable error (429 with `Retry-After`, or a `plan_limit` code); calls under the limit keep working.
- **[Usage metering](https://dabadata.com/docs/limits/index.md#usage)** - per environment and per day, in the console and at `GET /v1/project/usage`.
- **[Idle pause on Free](https://dabadata.com/docs/limits/index.md#idle-pause)** - a Free environment with no calls for 7 days is paused, and the next call wakes it up.

## Not built yet

Missing or planned today: server functions (your own code), left joins in views, more sign-in providers, sign-in on your own domain, live changes from writes made directly in Postgres, client libraries beyond JavaScript, and offline sync, push notifications, phone sign-in and multi-factor.

- **Server functions** - not built yet. dabadata does not run code you write, call outside APIs with a secret (beyond the model calls of actions), or receive third-party webhooks; [outbound webhooks](https://dabadata.com/docs/webhooks/index.md) tell your own server instead, and [scheduled actions](https://dabadata.com/docs/schedules/index.md) run your declared actions on a timetable. Declared [actions](https://dabadata.com/docs/rules/index.md#actions-protecting-counters-capacity-and-stock) cover multi-step writes with the server's rights, and an action can [call Claude or OpenAI](https://dabadata.com/docs/ai/index.md) with a key kept as a project secret.
- **[Left joins, and sorting or filtering on joined columns](https://dabadata.com/docs/views/index.md#joins)** - not available yet; view joins are inner.
- **[More sign-in providers](https://dabadata.com/docs/sign-in-providers/index.md#providers)** - Facebook, X, Twitch, Spotify, Bitbucket, Notion, Zoom, any OpenID Connect provider and SAML are not available yet; a provider that issues JWTs can be trusted as an issuer meanwhile.
- **[Sign-in on your own domain](https://dabadata.com/docs/sign-in-providers/index.md#what-users-see)** - planned; social sign-in returns through `https://dabadata.com` today.
- **[Live changes from writes made directly in Postgres](https://dabadata.com/docs/live/index.md#fan-out)** - planned (fan-out from logical replication); today changes made with `psql` or the SQL console are not streamed to subscribers.
- **[Client libraries beyond JavaScript](https://dabadata.com/docs/protocol/index.md)** - only the JavaScript client exists; the wire protocol is documented so other SDKs can be written.
- **Offline sync, push notifications, phone sign-in and multi-factor** - not built; there is no offline cache or mobile SDK, and multi-factor needs an identity provider such as Clerk or Auth0 declared as an issuer.
