Subchapter 2.49
references/DATA_COLLECTION.mdMarkdown19 KBView on GitHub
Creates CMS data collections for Wix CLI apps. The data collections extension allows your app to automatically create CMS collections when it’s installed on a site. Collections store structured data that can be accessed from dashboard pages, site pages, backend code, and external applications.
Important: This extension automatically enables the site’s code editor, which is required for the Wix Data APIs to work. Without this extension, apps using Data APIs would need the Wix user to manually enable the code editor on their site, which isn’t guaranteed. With the data collections extension, your app can reliably use Data APIs to read and write data in the collections.
Use wix generate --params with extensionType: DATA_COLLECTION. The only other param is collectionName (1-36 chars: letters, numbers, underscores, hyphens) — fields, permissions, displayName overrides, etc. are all edited after scaffolding in the generated file.
The CLI manages a shared aggregator file (data-collections.extension.ts) that imports every collection file and registers them in one extensions.dataCollections({...}) builder. The aggregator and src/extensions.ts are updated automatically — don’t edit them manually.
App namespace is REQUIRED for data collections to work. The namespace scopes your collection IDs to prevent conflicts between apps.
If app namespace is provided in the prompt:
<actual-namespace>/collection-suffixIf app namespace is NOT provided:
<app-namespace> in all code examples: <app-namespace>/collection-suffix<app-namespace> with your actual app namespace from Wix Dev Center”idSuffix): Use just the suffix, e.g., "products". The CLI uses collectionName from the scaffold params as the idSuffix for the generated entry."<app-namespace>/products" — MUST match idSuffix exactly (case-sensitive, no camelCase/PascalCase transformation)referencedCollectionId: Use the idSuffix only (not the full scoped ID) — the system resolves it automaticallyidSuffix is "product-recommendations", API calls use "<app-namespace>/product-recommendations" NOT "<app-namespace>/productRecommendations"The CLI scaffolds <CollectionName>.ts as a satisfies DataCollection default export. The scaffolded fields and dataPermissions are placeholders — replace them with your real schema, and set permissions per the Context-Based Permission Rules before shipping.
import type { DataCollection } from '@wix/astro/builders';
export const collectionIdSuffix = '<CollectionName>';
export default {
idSuffix: collectionIdSuffix,
displayName: '<CollectionName>',
displayField: 'title', // Field shown when referencing items
fields: [ /* field definitions */ ],
dataPermissions: { itemRead: 'ANYONE', itemInsert: 'PRIVILEGED', itemUpdate: 'PRIVILEGED', itemRemove: 'PRIVILEGED' },
indexes: [],
initialData: [],
} satisfies DataCollection;| Type | Description | Use Case |
|---|---|---|
TEXT | Single-line text | Names, titles |
RICH_TEXT | Formatted HTML text | Blog content |
RICH_CONTENT | Rich content with embedded media | Complex blog posts |
NUMBER | Decimal numbers | Prices, quantities |
BOOLEAN | True/false | Toggles, flags |
DATE | Date only | Birthdays |
DATETIME | Date with time | Timestamps |
TIME | Time only | Schedules |
IMAGE | Single image | Thumbnails |
DOCUMENT | File attachment | PDFs |
VIDEO | Video file | Media |
AUDIO | Audio file | Podcasts |
MEDIA_GALLERY | Multiple media | Galleries |
REFERENCE | Link to one item | Author → User |
MULTI_REFERENCE | Link to many items | Post → Tags |
ADDRESS | Structured address | Locations |
URL | URL validation | Links |
PAGE_LINK | Link to Wix page | Internal navigation |
LANGUAGE | Language code | Multi-language content |
OBJECT | JSON object | Flexible data |
ARRAY | Array of values | Generic arrays |
ARRAY_STRING | Array of strings | Tags list |
ARRAY_DOCUMENT | Array of documents | File collections |
ANY | Any type | Most flexible |
CRITICAL: OBJECT fields require objectOptions with a fields array. When using type: "OBJECT", you MUST include objectOptions: { fields: [] } — the API will reject OBJECT fields without it. Use an empty fields array if you don’t need a fixed schema (the object will still accept arbitrary JSON):
{
"key": "settings",
"displayName": "Settings",
"type": "OBJECT",
"objectOptions": { "fields": [] }
}⚠️
objectOptions: {}(without thefieldskey) is not valid and will cause a runtime error. Always includefields, even as an empty array.
For structured objects with a defined schema, list the nested fields inside objectOptions.fields:
{
"key": "triggerRules",
"displayName": "Trigger Rules",
"type": "OBJECT",
"objectOptions": {
"fields": [
{ "key": "url", "displayName": "URL Condition", "type": "TEXT" },
{
"key": "scrollDepth",
"displayName": "Scroll Depth %",
"type": "NUMBER"
},
{ "key": "dateStart", "displayName": "Start Date", "type": "DATE" }
]
}
}{
key: 'email', // required, lowerCamelCase ASCII
type: 'TEXT', // required, see Field Types above
displayName: 'Email Address', // optional, CMS label
description: "User's primary email", // optional, help text
encrypted: false, // optional, encrypt value at rest
// arrayOptions / objectOptions / referenceOptions / multiReferenceOptions
// only when type is ARRAY / OBJECT / REFERENCE / MULTI_REFERENCE
}| Property | Required | Description |
|---|---|---|
key | yes | Field identifier (lowerCamelCase) |
type | yes | Field data type (see Field Types) |
displayName | no | Label shown in CMS |
description | no | Help text |
encrypted | no | Encrypt value at rest |
There is no field-level required, defaultValue, or unique. The DevCenterDataCollectionField type does not accept them and TypeScript will reject the build. Use these alternatives instead:
initialData for seeded rows.indexes array (see Indexes). Uniqueness is an index-level concern, not a field-level one.The indexes array on the collection accepts entries shaped like:
indexes: [
{
fields: [{ path: 'email', order: 'ASC' }], // order is optional: 'ASC' | 'DESC'
unique: true, // optional, enforces uniqueness across items
},
{
fields: [
{ path: 'category' },
{ path: '_createdDate', order: 'DESC' },
],
},
],| Property | Required | Description |
|---|---|---|
fields | yes | One or more { path, order? } entries (composite index when more than one) |
fields[].path | yes | Field key to index |
fields[].order | no | 'ASC' (default) or 'DESC' |
unique | no | Enforce uniqueness on the indexed field(s) |
Leave indexes: [] when no custom indexing is needed; the _id index is created automatically.
lowerCamelCase, ASCII only (e.g., productName, isActive, createdAt)idSuffix): lower-kebab-case or lower_underscore (e.g., product-categories, blog_posts)"Product Name", "Is Active")Every collection includes: _id, _createdDate, _updatedDate, _owner
Access levels control who can read, create, update, and delete items in collections.
| Level | Description |
|---|---|
UNDEFINED | Not set (inherits defaults) |
ANYONE | Public access (including visitors) |
SITE_MEMBER | Any signed-in user (members and collaborators) |
SITE_MEMBER_AUTHOR | Signed-in users, but members only access own items |
CMS_EDITOR | Site collaborators with CMS Access permission |
PRIVILEGED | CMS administrators and privileged users |
Common patterns:
read: ANYONE, write: PRIVILEGEDread: SITE_MEMBER, write: SITE_MEMBER_AUTHORread: ANYONE, write: CMS_EDITORread: PRIVILEGED, write: PRIVILEGEDPermission hierarchy (most to least restrictive): PRIVILEGED > CMS_EDITOR > SITE_MEMBER_AUTHOR > SITE_MEMBER > ANYONE > UNDEFINED
CRITICAL: Permissions must match where and how the data is accessed. The consumer of the data determines the minimum permission level — setting permissions more restrictive than the access context will cause runtime failures (empty results or permission-denied errors).
Determine permissions by asking: “Who interacts with this data, and from where?”
| Access Context | Who Sees / Uses It | Implication |
|---|---|---|
Custom element widget (CUSTOM_ELEMENT_WIDGET) | Any site visitor (public) | Reads must be ANYONE. If the widget accepts input (e.g., reviews, submissions), inserts must also be ANYONE or SITE_MEMBER. |
| Embedded Script | Any site visitor (public) | Same as custom element widget — reads must be ANYONE. Writes depend on whether visitors can submit data. |
Dashboard Page (DASHBOARD_PAGE) | Site owner / collaborators only | Can use CMS_EDITOR or PRIVILEGED for all operations since only authorized users access the dashboard. |
| Backend code (site-side) | Runs in visitor context | If called from page code or site-side modules, the caller has visitor-level permissions — data must be readable/writable at the appropriate public level. |
| Backend code (elevated) | Runs with auth.elevate() from @wix/essentials | Can bypass permissions, but the collection still needs correct defaults for any non-elevated callers. |
Use SITE_MEMBER_AUTHOR on itemUpdate / itemRemove when members should only modify their own items (e.g., a member can edit only their own reviews).
How to apply this:
itemRead must be ANYONE (because the widget is public).itemRead: ANYONE (widget displays it) but itemInsert: CMS_EDITOR (only dashboard users add items). Each operation is independent.One-to-One / Many-to-One (REFERENCE):
{
"key": "category",
"displayName": "Category",
"type": "REFERENCE",
"referenceOptions": {
"referencedCollectionId": "categories"
}
}Many-to-Many (MULTI_REFERENCE):
{
"key": "tags",
"displayName": "Tags",
"type": "MULTI_REFERENCE",
"multiReferenceOptions": {
"referencedCollectionId": "tags"
}
}CRITICAL Constraints:
referencedCollectionId MUST be the idSuffix of another collection in the same planChanges to your data collections extension require releasing a new major version of your app. When a user updates to the new major version, their collections are updated as follows:
Important notes:
initialData is ignored during updates.Collections are for data, not configuration:
embeddedScriptParameters instead.panel.tsx (settings panel) instead. A widget-only blueprint usually needs zero collections.Common values that do not belong in a collection: colors, fonts, sizes, headlines, labels, messages, dates/times, coupon codes, display positions, feature toggles, frequencies, numeric thresholds.
Collections are for: business data (products, orders, inventory), user-generated content (reviews, comments, submissions), event logs, and multi-record relational data.
Each item in initialData must match the collection schema exactly:
lowerCamelCase and match the schemaTEXT → string, NUMBER → number, BOOLEAN → booleanDATE/DATETIME → use { "$date": "2024-01-15T10:30:00.000Z" } formatREFERENCE → provide the idSuffix of the referenced collectionRequest: “Create a collection for handling fees with example data”
Scaffold:
wix generate --params '{"extensionType":"DATA_COLLECTION","collectionName":"additional-fees"}'Edit the generated src/extensions/backend/data-collections/additional-fees.ts:
import type { DataCollection } from '@wix/astro/builders';
export const collectionIdSuffix = 'additional-fees';
export default {
idSuffix: collectionIdSuffix,
displayName: 'Additional Fees',
displayField: 'title',
fields: [
{ key: 'title', displayName: 'Fee Title', type: 'TEXT' },
{ key: 'amount', displayName: 'Fee Amount', type: 'NUMBER' },
],
dataPermissions: {
itemRead: 'ANYONE',
itemInsert: 'PRIVILEGED',
itemUpdate: 'PRIVILEGED',
itemRemove: 'PRIVILEGED',
},
indexes: [],
initialData: [
{ title: 'Handling Fee', amount: 5 },
{ title: 'Gift Wrapping', amount: 3.5 },
],
} satisfies DataCollection;Request: “Create collections for products and categories with relationships”
Run wix generate --params twice — once with collectionName: "categories" and once with collectionName: "products". Then edit src/extensions/backend/data-collections/products.ts to add a REFERENCE field pointing at categories (referenceOptions: { referencedCollectionId: "categories" }). The aggregator data-collections.extension.ts is updated by the CLI automatically.
Soft Delete: Add isDeleted (BOOLEAN), defaulted at the insert path
Status/Workflow: Add status (TEXT) with values like draft/pending/published
URL Slug: Add slug (TEXT) plus a { fields: [{ path: 'slug' }], unique: true } entry in indexes for SEO-friendly URLs
Owner Tracking: Add createdBy (REFERENCE → custom collection, not Members)
Note: For owner tracking, create a custom collection for users rather than referencing Wix Members directly.
@wix/data