.agents/features/tables.md
A built-in relational database feature that lets users store structured data directly within Activepieces, without needing an external database. Tables support typed fields, cell-level storage, per-row webhooks that fire flow automations, and a rich spreadsheet-like editor in the UI. They are tightly integrated with the flow engine through the Tables piece, which provides trigger and action steps for reacting to and manipulating table data.
packages/server/api/src/app/tables/table/table.service.ts — table CRUD, export, webhook managementpackages/server/api/src/app/tables/table/table.controller.ts — table endpointspackages/server/api/src/app/tables/table/table.entity.ts — Table entitypackages/server/api/src/app/tables/table/table-webhook.entity.ts — TableWebhook entitypackages/server/api/src/app/tables/field/field.service.ts — field CRUDpackages/server/api/src/app/tables/field/field.controller.ts — field endpointspackages/server/api/src/app/tables/field/field.entity.ts — Field entitypackages/server/api/src/app/tables/record/record.service.ts — record CRUD, bulk opspackages/server/api/src/app/tables/record/record.controller.ts — record endpointspackages/server/api/src/app/tables/record/record.entity.ts — Record entitypackages/server/api/src/app/tables/record/cell.entity.ts — Cell entitypackages/server/api/src/app/tables/record/record-side-effects.ts — fires TableWebhook flows on record eventspackages/server/api/src/app/tables/tables.module.ts — module registrationpackages/shared/src/lib/automation/tables/table.ts — Table schemapackages/shared/src/lib/automation/tables/field.ts — Field schema and FieldType enumpackages/shared/src/lib/automation/tables/record.ts — Record schemapackages/shared/src/lib/automation/tables/cell.ts — Cell schemapackages/shared/src/lib/automation/tables/table-webhook.ts — TableWebhook schemapackages/shared/src/lib/automation/tables/dto/ — request/response DTOspackages/web/src/app/routes/tables/id/index.tsx — the table editor page (react-data-grid based)packages/web/src/features/tables/components/ap-table-header.tsx — header bar with table name, actionspackages/web/src/features/tables/components/ap-table-state-provider.tsx — state context for the tablepackages/web/src/features/tables/components/ap-field-header.tsx — column header with field actionspackages/web/src/features/tables/components/table-columns.tsx — column definitions for react-data-gridpackages/web/src/features/tables/components/editable-cell.tsx — cell editing wrapperpackages/web/src/features/tables/components/ap-table-actions-menu.tsx — table-level action menupackages/web/src/features/tables/components/import-table-dialog.tsx — CSV import dialogpackages/web/src/features/tables/components/new-field-popup.tsx — add field popuppackages/web/src/features/tables/hooks/table-hooks.ts — React Query hooks for tables/fields/recordspackages/web/src/features/tables/stores/store/ap-tables-client-state.tsx — optimistic client-side statepackages/web/src/features/tables/stores/store/ap-tables-server-state.ts — server-synced statepackages/web/src/features/tables/api/tables-api.ts — table API callspackages/web/src/features/tables/api/fields-api.ts — field API callspackages/web/src/features/tables/api/records-api.ts — record API callsTEXT, NUMBER, DATE, STATIC_DROPDOWNRECORD_CREATED, RECORD_UPDATED, RECORD_DELETEDpackages/pieces/core/tables/; provides trigger and action steps that interact with tables via the internal APITable: id, projectId, name, folderId (nullable), externalId, trigger (nullable), status (nullable). Relations: project, folder, fields[], records[], tableWebhooks[].
Field: id, tableId, projectId, name, type, externalId, data (JSONB — e.g., { options: [{ value }] } for STATIC_DROPDOWN).
TEXT, NUMBER, DATE, STATIC_DROPDOWNAP_MAX_FIELDS_PER_TABLE (default 100)Record: id, tableId, projectId. Relations: table, cells[].
Cell: id, recordId, fieldId, projectId, value (VARCHAR). Unique constraint: (projectId, fieldId, recordId).
TableWebhook: id, projectId, tableId, flowId, events[] (string array).
RECORD_CREATED, RECORD_UPDATED, RECORD_DELETEDtable.create() — creates table + optional fieldstable.list() — paginated with optional row count, name filter, folder filter, externalIds filtertable.update() — rename, move to folder, change trigger/statustable.delete() — cascades to fields, records, cells, webhookstable.exportTable() — returns fields + rows as JSONtable.createWebhook() / table.deleteWebhook() — link table events to flowsrecord.create() — bulk insert (max 50 per batch, transactional), validates field countrecord.list() — with filters (EQ, NEQ, GT, GTE, LT, LTE, CO, EXISTS, NOT_EXISTS)record.update() — update cells (empty fields unchanged)record.delete() / record.deleteAll() — bulk deleteAll table / field / record routes use securityAccess.project([...], <permission>, <resource>). The required permission per resource:
GET /v1/tables, GET /v1/tables/:id, GET /v1/fields, GET /v1/fields/:id, GET /v1/records, GET /v1/records/:id): READ_TABLEPOST /v1/tables, POST /v1/tables/:id, DELETE /v1/tables/:id, POST /v1/fields, POST /v1/fields/:id, DELETE /v1/fields/:id, POST /v1/records, POST /v1/records/:id, DELETE /v1/records): WRITE_TABLEDefault project roles: ADMIN and EDITOR have both; VIEWER has only READ_TABLE. Custom roles inherit whatever permissions are configured.
ENGINE and SERVICE principals skip the per-role permission check entirely — ENGINE is gated on principal.projectId === projectId and SERVICE on platform-equality only — so flow steps that call the records API and service API keys are unaffected by the role-permission model.
When adding a new route (read or write) on tables / fields / records, the permission argument to securityAccess.project(...) is required; passing undefined short-circuits the rbac check to allow any project member.
After record create/update/delete, recordSideEffects.handleRecordsEvent():
Tables piece (packages/pieces/core/tables/) provides: