Skip to main content
Memberstack Docs
Dashboard

Data Tables

Data Tables let you store and query structured, app-scoped data from your server. The Admin Package exposes them under memberstack.dataTables, with methods to read table schemas and to create, query, update, and delete records.

/admin-node-package/data-tables.md
Before You Start
  • Initialize the Admin Package with your secret key as shown in the Quick Start guide
  • Create your tables and fields in the Memberstack dashboard (Data Tables) first — the Admin Package reads and writes records, it does not create tables or fields
  • The Admin API has full access and ignores per-table access rules (createRule/readRule/etc.)
  • Records are environment-scoped: a sandbox key (sk_sb_…) only sees sandbox records

Overview

Every method takes a table (the table key from your dashboard, e.g. "contacts", or a table id like "tbl_…"). Record values live under a data object keyed by your field keys. Responses are wrapped in { data }, the same as the member methods.

MethodDescription
dataTables.list()List all tables and their fields
dataTables.get()Get one table by key or id
dataTables.createRecord()Create a record
dataTables.getRecord()Get one record by id
dataTables.queryRecords()Query records (findMany / findUnique)
dataTables.updateRecord()Update a record
dataTables.deleteRecord()Delete a record

Field Types

Each table field has a type that determines how its value is stored and returned. Fields are defined in the dashboard (Data Tables); the type is reported on each field in list() / get().

TypeDescription
TEXTPlain text (also TEXT_FILTERABLE, TEXT_UNIQUE, EMAIL, URL variants)
NUMBERInteger value
DECIMALDecimal value (see the note on string vs number below)
BOOLEANtrue / false
DATEISO date-time string
REFERENCEA link to one record in another table
REFERENCE_MANYLinks to many records in another table
MEMBER_REFERENCEA link to a single member
MEMBER_REFERENCE_MANYLinks to many members

List Data Tables

Retrieve every table in your app along with its field definitions.

const { data } = await memberstack.dataTables.list();

console.log(data.tables);

Response:

{
  data: {
    tables: [
      {
        id: "tbl_abc123",
        key: "contacts",
        name: "Contacts",
        createRule: "AUTHENTICATED",
        readRule: "PUBLIC",
        updateRule: "AUTHENTICATED_OWN",
        deleteRule: "ADMIN_ONLY",
        createdAt: "2026-01-15T10:30:00.000Z",
        updatedAt: "2026-01-15T10:30:00.000Z",
        fields: [
          {
            id: "fld_1",
            key: "name",
            name: "Name",
            type: "TEXT",
            required: true,
            defaultValue: null,
            tableOrder: 1,
            referencedTableId: null
          }
          // ...more fields
        ]
      }
      // ...more tables
    ]
  }
}

Get a Data Table

Fetch a single table (and its fields) by key or id.

const { data } = await memberstack.dataTables.get({
  table: "contacts"
});

console.log(data.key);    // "contacts"
console.log(data.fields); // [{ key: "name", type: "TEXT", ... }, ...]
Not Found

Requesting a table that does not exist rejects with a 404 and the message "Data table not found".

Create a Record

Create a record by passing the table and a data object keyed by your field keys.

const { data: record } = await memberstack.dataTables.createRecord({
  table: "contacts",
  data: {
    name: "Ada Lovelace",
    score: 9.5,
    active: true
  },
  // Optional: associate the record with a member (must exist in this app/env)
  memberId: "mem_abc123"
});

console.log(record.id);

Response:

{
  data: {
    id: "rec_xyz789",
    tableKey: "contacts",
    data: {
      name: "Ada Lovelace",
      score: "9.5",   // DECIMAL is a string here — see note below
      active: true
    },
    createdAt: "2026-01-15T10:30:00.000Z",
    updatedAt: "2026-01-15T10:30:00.000Z",
    internalOrder: 42
  }
}
Required and Optional Parameters
  • Required:
    • table — the table key or id
    • data — an object of field values (must be an object, not an array)
  • Optional:
    • memberId — associate the record with a member; the member must exist in this app and environment

Get a Record

Fetch a single record by id. This is a convenience wrapper around a findUnique query, so the record is returned under data.record.

const { data } = await memberstack.dataTables.getRecord({
  table: "contacts",
  recordId: "rec_xyz789"
});

console.log(data.record.data.name);  // "Ada Lovelace"
console.log(data.record.data.score); // 9.5  (a number on reads)
Not Found

If the record id does not exist, getRecord() rejects with a 404 and the message "Record not found".

Query Records

Use queryRecords() for filtering, sorting, pagination, relationships, and counts. It accepts a Prisma-like query with either findMany (many records) or findUnique (one record by id) — exactly one of the two.

const { data } = await memberstack.dataTables.queryRecords({
  table: "contacts",
  query: {
    findMany: {
      where: { active: { equals: true }, score: { gte: 5 } },
      orderBy: { score: "desc" },
      take: 10
    }
  }
});

console.log(data.records);    // matching records
console.log(data.pagination); // { limit, endCursor, hasMore }
Response Shape
  • findMany{ data: { records, pagination } } (pagination is present when take is set)
  • findMany with _count: true{ data: { _count } }
  • findUnique{ data: { record } }

Query Options (findMany)

OptionTypeDescription
whereobjectFilter conditions (see operators below)
includeobjectInclude related records or counts
selectobjectSelect specific fields (cannot use with include)
orderByobject | arraySort results
takenumberLimit number of results (max 100)
skipnumberOffset pagination (max 10000, cannot use with after)
afternumber | stringCursor pagination — pass the previous endCursor (cannot use with skip)
_countbooleanReturn only the count of matching records

findUnique requires where.id and supports include / select only — pagination and ordering are not allowed.

Where Operators

Filter conditions support the following operators:

OperatorExample
equals{ score: { equals: 9.5 } }
not{ status: { not: 'archived' } }
in{ status: { in: ['active', 'pending'] } }
notIn{ status: { notIn: ['deleted'] } }
lt / lte{ score: { lte: 100 } }
gt / gte{ score: { gte: 50 } }
contains{ name: { contains: 'Ada' } }
startsWith{ name: { startsWith: 'A' } }
endsWith{ email: { endsWith: '@acme.com' } }

Combine conditions with AND, OR, and NOT, e.g. where: { OR: [{ score: { gte: 90 } }, { active: { equals: true } }] }.

Update a Record

Update a record by id. Only the fields you include in data are changed.

const { data: record } = await memberstack.dataTables.updateRecord({
  table: "contacts",
  recordId: "rec_xyz789",
  data: {
    score: 8.25
  }
});

console.log(record.data.score); // "8.25"

Tips for updating records:

  • Pass only the fields you want to change — other fields are left untouched
  • data must be a non-empty object
  • For REFERENCE / MEMBER_REFERENCE fields, use connect / disconnect (e.g. { author: { connect: { id: "rec_…" } } })

Delete a Record

Delete a record by id. The deleted record is returned.

const { data: record } = await memberstack.dataTables.deleteRecord({
  table: "contacts",
  recordId: "rec_xyz789"
});

console.log(`Deleted record: ${record.id}`);
Important

Deleting a record is permanent and cannot be undone. Implement a confirmation step and back up important data if needed.

A Note on DECIMAL Fields

DECIMAL: string vs number

DECIMAL field values are returned as strings from createRecord(), updateRecord(), and deleteRecord(), but as numbers from getRecord() and queryRecords(). Coerce with Number(record.data.score) if you need a consistent numeric type.

Error Handling

Errors reject with an object containing a code and message. "Not found" cases return a 404 status; validation problems return 400.

try {
  await memberstack.dataTables.getRecord({
    table: "contacts",
    recordId: "rec_missing"
  });
} catch (error) {
  // { code: "generic-message", message: "Record not found" }
  console.error(error.message);
}
MessageWhen
Data table not foundThe table key/id does not exist (404)
Record not foundThe record id does not exist (404)
Member not foundcreateRecord memberId is not in this app/env (404)
data must be an objectcreateRecord/updateRecord data is not an object (400)
data cannot be emptyupdateRecord data is an empty object (400)
Either query.findMany or query.findUnique parameter is requiredqueryRecords query has neither (400)