Appbricx
Docs
FeaturesPricingStart free

Get started

OverviewWhat Appbricx isQuickstart with a coding agentQuickstart with the builderCore concepts

Guides

Data and tablesAccess and rolesBusiness rulesSign-inCustom screensRealtime and topicsWorkflows, schedules and webhooksServer functionsAI in your appPaymentsFilesMessagesIntegrationsVerifyPublishing, domains and rollbackOperating your appExport and self-hostSelf-host install

Tutorials

Build a booking app with Claude CodeMulti-user todo listClient portalSlack on new sign-upTemplates

Reference

Reference homeFrontend SDKHTTP APIMCP toolsCLIIntegrations catalogContract formatAI key resolutionRun Appbricx locally

Data

Read and write rows of the app's own tables. Every call is a request to the app's data API under the signed-in user's identity, so the database's per-role row-level security decides what each user sees and changes.

12 membersSDK referenceGuide: Use your data from React

On this page
  1. Working set
  2. app.rows
  3. app.loading
  4. app.revision
  5. Queries
  6. app.query
  7. app.get
  8. Writes
  9. app.create
  10. app.update
  11. app.remove
  12. app.transition
  13. React hooks
  14. useEntityQuery
  15. useRecord
  16. useAggregate
  17. Types

Use query and get (or the hooks) for anything that lists, counts or presents records: they run server-side and stay correct however large a table grows. rows() is a bounded working set (the newest 200 rows the user may read) for small lookups.

Owner columns (user_id, org_id, created_by) are stamped by the server. Pass only the row's own fields.

Working set

app.rowsmethod

The table's working set: the newest rows (at most 200) the user may read, loaded on first use. Synchronous; the component re-renders as rows arrive or change.

app.rows(entity: string): Row[]

Parameters

NameTypeDescription
entityrequiredstringThe table name, as in the contract's entities[].name.
Returns
Row[] (empty while loading).
Errors
Does not throw.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const categories = app.rows("categories");
return <select>{categories.map((c) => <option key={String(c.id)}>{String(c.name)}</option>)}</select>;

Relatedapp.loadingapp.queryGET /__appbricx/api/v1/:table

Source: packages/appkit/src/kits/primitives/app-handle.ts:167

app.loadingmethod

True while the table's working set is still loading.

app.loading(entity: string): boolean

Parameters

NameTypeDescription
entityrequiredstringThe table name.
Returns
boolean.
Errors
Does not throw.
Permissions
Local state.
Example
if (app.loading("categories")) return <Skeleton />;

Relatedapp.rows

Source: packages/appkit/src/kits/primitives/app-handle.ts:168

app.revisionmethod

A number that moves whenever the table changes (a write here or a realtime event). Put it in a useEffect dependency list to refetch a query.

app.revision(entity: string): number

Parameters

NameTypeDescription
entityrequiredstringThe table name.
Returns
number (0 when the runtime doesn't track revisions).
Errors
Does not throw.
Permissions
Local state.
Example
useEffect(() => {
  void app.query("tickets", { where: { status: "open" } }).then((r) => setOpen(r.total));
}, [app, app.revision("tickets")]);

Relatedapp.liveapp.query

Source: packages/appkit/src/kits/primitives/app-handle.ts:171

Queries

app.querymethod

A server-side filtered, sorted page of rows plus the total match count.

app.query(entity: string, q?: AppQuery): Promise<{ rows: Row[]; total: number }>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
qoptionalAppQuery{ where?, sort?, limit?, offset? }. where is equality filters (ANDed); sort is { field, dir? } with dir "asc" by default; limit defaults to 50 (the server caps it at 500).
Returns
{ rows: Row[]; total: number }. total counts every match, not just this page.
Errors
  • The server's message: TABLE_FORBIDDEN when the role may not read the table, PARAMS_INVALID for bad filters, RATE_LIMITED past the project's request budget.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const { rows, total } = await app.query("tickets", {
  where: { status: "open", assignee: app.me("agent") ?? "" },
  sort: { field: "created_at", dir: "desc" },
  limit: 20,
});

RelateduseEntityQueryGET /__appbricx/api/v1/:table

Source: packages/appkit/src/kits/primitives/app-handle.ts:173

app.getmethod

One row by id.

app.get(entity: string, id: string): Promise<Row | null>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
idrequiredstringThe row's id.
Returns
The row, or null when it doesn't exist or row-level security hides it.
Errors
  • The server's message for a refused read (TABLE_FORBIDDEN) or a failed request.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const ticket = await app.get("tickets", app.params.id);
if (!ticket) return <p>This ticket no longer exists.</p>;

RelateduseRecordGET /__appbricx/api/v1/:table/:id

Source: packages/appkit/src/kits/primitives/app-handle.ts:174

Writes

app.createmethod

Insert a row. Owner columns are stamped server-side, before-write rules run, and a row-changed event fires (workflows on created run).

app.create(entity: string, values: Row): Promise<Row>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
valuesrequiredRowThe row's own fields. Leave out id, owner columns and timestamps.
Returns
The created row, with its id.
Errors
  • A unique-constraint conflict, verbatim ("That booking already exists — resource + slot must be unique."), checked locally first when the runtime knows the field is unique.
  • RULE_REFUSED with the rule's message when a before-write rule says no; TABLE_FORBIDDEN when the role may not create.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const row = await app.create("tickets", { title: "Printer jam", priority: "high" });
app.navigate(`/tickets/${row.id}`);

RelatedPOST /__appbricx/api/v1/:tableapp.canGuides rules

Source: packages/appkit/src/kits/primitives/app-handle.ts:176

app.updatemethod

Patch a row. Only the fields you pass change.

app.update(entity: string, id: string, patch: Row): Promise<void>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
idrequiredstringThe row's id.
patchrequiredRowFields to change.
Returns
Resolves when saved.
Errors
  • E_LIFECYCLE_DIRECT_WRITE when the patch touches a lifecycle field: use transition.
  • RULE_REFUSED, TABLE_FORBIDDEN, or a unique-constraint conflict message.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
await app.update("tickets", id, { priority: "low" });

RelatedPATCH /__appbricx/api/v1/:table/:idapp.transition

Source: packages/appkit/src/kits/primitives/app-handle.ts:177

app.removemethod

Delete a row.

app.remove(entity: string, id: string): Promise<void>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
idrequiredstringThe row's id.
Returns
Resolves when deleted.
Errors
  • TABLE_FORBIDDEN when the role may not delete, or the server's message.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
if (confirm("Delete this ticket?")) await app.remove("tickets", id);

RelatedDELETE /__appbricx/api/v1/:table/:idapp.can

Source: packages/appkit/src/kits/primitives/app-handle.ts:178

app.transitionmethod

Move a lifecycle enum field (status) along the contract's transition graph. A plain write to a lifecycle field is refused.

app.transition(entity: string, id: string, field: string, to: string): Promise<void>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
idrequiredstringThe row's id.
fieldrequiredstringThe lifecycle field, e.g. "status".
torequiredstringThe target state, e.g. "resolved".
Returns
Resolves when the move is saved.
Errors
  • E_TRANSITION_FORBIDDEN when the graph has no edge from the current state; E_TRANSITION_ROLE when the role may not make this move; E_FIELD_NOT_LIFECYCLE for an ordinary field.
Permissions
The transition plane checks the graph and the role restrictions; row-level security still applies to the row.
Example
await app.transition("tickets", id, "status", "resolved");

RelatedPATCH /__appbricx/api/v1/:entity/:id/transitionapp.update

Source: packages/appkit/src/kits/primitives/app-handle.ts:180

React hooks

useEntityQueryfunction

A page of rows plus the total match count, as a resource that refetches when the table's revision moves. The previous page stays on screen while the next loads.

useEntityQuery(entity: string, q: EntityQuery, opts?: { … }): Resource<QueryResult>

Parameters

NameTypeDescription
entityrequiredstringThe table name ("" disables the hook).
qrequiredEntityQueryEntityQuery: { filter?, sort?, limit?, offset?, search? }. filter clauses take every op in QueryFilterOp (eq, in, lt, contains, range…).
optsoptional{ enabled?: boolean; keepPrevious?: boolean }{ enabled?: boolean; keepPrevious?: boolean } (keepPrevious defaults to true).
Returns
Resource<QueryResult>: { data, loading, refreshing, error, retry }.
Errors
  • Never throws; a failed load sets error and retry() tries again.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const tickets = useEntityQuery("tickets", {
  filter: [{ field: "status", op: "in", value: ["open", "pending"] }],
  sort: { field: "created_at", dir: "desc" },
  limit: 25,
});
if (tickets.loading) return <Skeleton />;
return <List rows={tickets.data?.rows ?? []} total={tickets.data?.total ?? 0} />;

Relatedapp.queryGET /__appbricx/api/v1/:table

Source: packages/appkit/src/kits/runtime.tsx:251

useRecordfunction

One record by id, as a resource. data is null when the record doesn't exist (or row-level security hides it), undefined while loading.

useRecord(entity: string, id: string | undefined): Resource<Row | null>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
idrequiredstring | undefinedThe row id; undefined disables the hook.
Returns
Resource<Row | null>.
Errors
  • Never throws; failures set error.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const ticket = useRecord("tickets", params.id);
if (ticket.data === null) return <p>Not found</p>;

Relatedapp.get

Source: packages/appkit/src/kits/runtime.tsx:266

useAggregatefunction

A server-side count, sum, avg, min or max over the matching rows, as a resource.

useAggregate(entity: string, a: AggregateSpec): Resource<number>

Parameters

NameTypeDescription
entityrequiredstringThe table name.
arequiredAggregateSpecAggregateSpec: { metric, field?, filter? }. field is required unless metric is "count".
Returns
Resource<number>.
Errors
  • Never throws; failures set error.
Permissions
Runs through the app's data API as the signed-in user: the table's per-role access rules and row-level security decide which rows it can touch. A signed-out visitor acts as a guest.
Example
const revenue = useAggregate("orders", {
  metric: "sum", field: "total",
  filter: [{ field: "created_at", op: "range", value: "this_month" }],
});

RelatedGET /__appbricx/api/v1/:table/aggregate

Source: packages/appkit/src/kits/runtime.tsx:284

Types

type AppQuery = {
    where?: Record<string, string | number | boolean | null>;
    sort?: {
        field: string;
        dir?: "asc" | "desc";
    };
    limit?: number;
    offset?: number;
}

Source: packages/appkit/src/kits/primitives/app-handle.ts:38

type Row = Record<string, unknown>

Source: packages/appkit/src/kits/query.ts:16

type EntityQuery = {
    filter?: QueryFilter[];
    sort?: QuerySort;
    limit?: number;
    offset?: number;
    search?: {
        field: string;
        q: string;
    };
}

Source: packages/appkit/src/kits/query.ts:30

type QueryFilter = {
    field: string;
    op: QueryFilterOp;
    value?: unknown;
}

Source: packages/appkit/src/kits/query.ts:27

type QueryFilterOp = "eq" | "neq" | "in" | "not_in" | "lt" | "lte" | "gt" | "gte" | "contains" | "is_null" | "is_not_null" | "range"

Source: packages/appkit/src/kits/query.ts:18

type QuerySort = {
    field: string;
    dir: "asc" | "desc";
}

Source: packages/appkit/src/kits/query.ts:28

type QueryResult = {
    rows: Row[];
    total: number;
}

Source: packages/appkit/src/kits/query.ts:41

type AggregateSpec = {
    metric: AggregateMetric;
    field?: string;
    filter?: QueryFilter[];
}

Source: packages/appkit/src/kits/query.ts:44

type AggregateMetric = "count" | "sum" | "avg" | "min" | "max"

Source: packages/appkit/src/kits/query.ts:43

type Resource<T> = {
    data: T | undefined;
    loading: boolean;
    refreshing: boolean;
    error: Error | undefined;
    retry: () => void;
}

Source: packages/appkit/src/kits/runtime.tsx:183

On this page

  1. Working set
  2. app.rows
  3. app.loading
  4. app.revision
  5. Queries
  6. app.query
  7. app.get
  8. Writes
  9. app.create
  10. app.update
  11. app.remove
  12. app.transition
  13. React hooks
  14. useEntityQuery
  15. useRecord
  16. useAggregate
  17. Types
Appbricx

The backend, runtime and hosting for apps your coding agent builds. On our cloud, in yours, or on your own servers.

Features

Coding agents and MCPVerify testingBuilder consolePostgres databaseData APIRealtimeRow-level securitySign-in and authPaymentsWorkflows and jobsAI in your appIntegrationsBackups and rollbackHosting and domainsSelf-host and exportAll features

Product

ShowcasePricingFor coding agentsTemplatesPrivate cloudBring your own AI keyFAQ

Compare

Appbricx vs SupabaseLovable alternativeBolt alternativeFor freelancersFor agencies

Resources

DocumentationReferenceBlogSupportContact

© 2026 Appbricx. All rights reserved.

TermsPrivacyCookiesAcceptable Use