# Bases

- Human documentation: [https://docs.univer.ai/reference/facade/bases](https://docs.univer.ai/reference/facade/bases)

- Agent Markdown: [https://docs.univer.ai/reference/facade/bases.md](https://docs.univer.ai/reference/facade/bases.md)

- Requested language: `en-US`

- Content language: `en-US`

- Documentation version: `1.0.0-rc.0`

- Source: [facade/bases.mdx](https://github.com/dream-num/documentation/blob/dev/content/reference/facade/bases.mdx)

---

| Packages | `@univerjs-pro/bases`, `@univerjs-pro/bases-ui`, `@univerjs-pro/bases-dashboard`, `@univerjs-pro/bases-thread-comment`, `@univerjs-pro/bases-exchange-client` |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |

Facade APIs for Base units, tables, fields, records, views, ranges, and workbench UI state.

> Import `@univerjs-pro/bases/facade` and, for UI APIs, `@univerjs-pro/bases-ui/facade`.

## Unit access

```typescript
// univerAPI
createBase(snapshot?: Partial<IBaseSnapshot>, options?: ICreateUnitOptions): FBase
getActiveBase(): FBase | null
getBase(baseId: string): FBase | null
getBases(): FBase[]
```

## Permissions

`FBase.getPermission()` returns unit-level Edit, Copy, Export, and Comment points. Tables, fields, records, views, Pivot Views, and Dashboards expose `getPermission()` for effective object-level editing.

```typescript
import { UnitAction } from '@univerjs/protocol'

const base = univerAPI.getActiveBase()
if (!base) throw new Error('No active Base')

await base.getPermission().setPoint(UnitAction.Copy, false)
await base.getTables()[0]?.getPermission().setReadOnly()
```

An object's `canEdit()` applies the Base and parent-object permissions as ceilings; enabling a child does not override a read-only parent.

## Pivot Views and Dashboards

Import `@univerjs-pro/bases-dashboard/facade` to extend `FBase`:

```typescript
import '@univerjs-pro/bases-dashboard/facade'

const base = univerAPI.getActiveBase()
const table = base?.getTables()[0]
if (!base || !table) throw new Error('Base table not found')

const pivot = base.createPivotView('Revenue by region', table.getId())
const dashboard = base.createDashboard('Executive overview')

dashboard.addPivotChart(table.getId(), pivot.getId(), {
  layout: { column: 0, row: 0, columnSpan: 6, rowSpan: 6 },
})
```

`FBase` provides `getDashboards()`, `getDashboardById()`, `createDashboard()`, `getPivotViews()`, `getPivotView()`, and `createPivotView()`. Pivot View Facades expose configuration and calculation; Dashboard Facades manage Pivot charts, table filters, text, images, Formula Shapes, and widget order.

## Record attachments and comments

```typescript
const record = univerAPI.getActiveBase()?.getTables()[0]?.getRecords()[0]
const attachments = record?.getAttachments('files') ?? []
record?.deleteAttachments('files', attachments)
```

Import `@univerjs-pro/bases-thread-comment/facade` to add row-anchored comment helpers:

```typescript
import '@univerjs-pro/bases-thread-comment/facade'

await record?.createCommentAsync('Confirm this record.', { id: 'review-record-1' })
const comments = await record?.listCommentsAsync()
```

## FBase

| Method                           | Description                                     |
| -------------------------------- | ----------------------------------------------- |
| `getBase`                        | Get the underlying `BaseDataModel`.             |
| `getId`                          | Get the Base unit id.                           |
| `save`                           | Serialize the complete current Base snapshot.   |
| `getName`, `setName`             | Read or update the Base name.                   |
| `getTables`                      | List existing tables in table order.            |
| `getTableById`, `getTableByName` | Resolve a table.                                |
| `insertTable`                    | Insert a table with a generated default schema. |
| `deleteTable`                    | Delete a table by facade or id.                 |
| `duplicateTable`                 | Copy a table, optionally including records.     |
| `getSchema`                      | Get a compact schema without record values.     |

```typescript
getBase(): BaseDataModel
getId(): string
save(): IBaseSnapshot
getName(): string
setName(name: string): void
getTables(): FBaseTable[]
getTableById(tableId: string): FBaseTable | null
getTableByName(displayName: string): FBaseTable | null
insertTable(displayName: string, options?: { index?: number; table?: Partial<Omit<ITableSnapshot, 'id'>>; primaryFieldName?: string }): FBaseTable
deleteTable(table: FBaseTable | string): boolean
duplicateTable(table: FBaseTable | string, options?: { includeRecords?: boolean; regenerateViewIds?: boolean }): FBaseTable
getSchema(): IBaseSchemaSnapshot
```

### Table names

A table display name must:

* contain 1–31 characters;
* not start or end with an apostrophe;
* not contain `: \ / ? * [ ]`;
* be unique within the Base, ignoring case.

`insertTable()` and `FBaseTable.setName()` throw when a name violates this contract. Renaming a table does not change the stable identifier returned by `getFormulaName()`.

## FBaseTable

| Category  | Methods                                                                                           |
| --------- | ------------------------------------------------------------------------------------------------- |
| Identity  | `getBase`, `getTable`, `getId`, `getName`, `setName`, `getFormulaName`, `getSchema`               |
| Hierarchy | `getHierarchyFieldId`, `setHierarchyField`                                                        |
| Search    | `search`                                                                                          |
| Fields    | `getPrimaryFieldId`, `getPrimaryField`, `getFields`, `getFieldById`, `getFieldByName`, `addField` |
| Records   | `getRecords`, `getRecordById`, `queryRecords`, `addRecord`, `addRecords`, `deleteRecords`         |
| Ranges    | `getRange`, `getDataRange`                                                                        |
| Views     | `getViews`, `getViewById`, `getViewByName`, `createView`                                          |

```typescript
getBase(): BaseDataModel
getTable(): ITableSnapshot
getId(): string
getHierarchyFieldId(): string
setHierarchyField(fieldId: string | null): boolean
getName(): string
setName(displayName: string): boolean
getFormulaName(): string
search(request: Omit<IBaseTableSearchRequest, 'table' | 'rows'>, viewId?: string): IBaseTableSearchResult
getPrimaryFieldId(): string
getPrimaryField(): FBaseTableField
getFields(): FBaseTableField[]
getFieldById(fieldId: string): FBaseTableField | null
getFieldByName(fieldName: string): FBaseTableField | null
addField(name: string, type: BaseFieldType, options?: IBaseAddFieldOptions | IBaseAddFormulaFieldOptions): FBaseTableField
getRecords(): FBaseTableRecord[]
getRecordById(recordId: string): FBaseTableRecord | null
queryRecords(options?: IListRecordOptions): IQueryRecordsResult
addRecord(values: Record<FieldId, BaseCellValue>, fieldKey?: BaseFieldKeyEnum, record?: Partial<Omit<IRecordSnapshot, 'id'>>): FBaseTableRecord
addRecords(records: Array<{ values: Record<FieldId, BaseCellValue>; fieldKey?: BaseFieldKeyEnum; record?: Partial<Omit<IRecordSnapshot, 'id'>> }>): FBaseTableRecord[]
deleteRecords(recordIds: string[]): boolean
getRange(row: number, column: number, numRows?: number, numColumns?: number): FBaseTableRange
getDataRange(): FBaseTableRange
getViews(): FBaseTableView[]
getViewById(viewId: string): FBaseTableView | null
getViewByName(viewName: string): FBaseTableView | null
createView(name: string, type: BaseViewType, options?: { index?: number; view?: Partial<Omit<IViewSnapshot, 'id'>> }): FBaseTableView
getSchema(): IBaseTableSchemaSnapshot
```

Formula fields use OOXML structured references and require `IBaseAddFormulaFieldOptions.externalReferences`. Use `getFormulaName()` instead of the display name because renaming a table does not change its stable formula name. Pass `[]` only when the formula has no external Unit qualifier.

```ts
const formulaTableName = table.getFormulaName()
const total = table.addField('Total', univerAPI.Enum.BaseFieldType.Formula, {
  field: {
    config: {
      formula: `=SUM(${formulaTableName}[[#This Row],[Amount]],${formulaTableName}[[#This Row],[Tax]])`,
    },
  },
  externalReferences: [],
})
```

## FBaseTableField

```typescript
getId(): string
getField(): IFieldSnapshot
getName(): string
getType(): BaseFieldType
getConfig(): FieldConfig
getDefaultValue(): IFieldSnapshot['defaultValue']
getDescription(): string | undefined
isReadonly(): boolean
setName(name: string): boolean
setConfig(config: FieldConfig, options?: IBaseFormulaFieldWriteOptions): boolean
setDefaultValue(defaultValue: IFieldSnapshot['defaultValue']): boolean
update(patch: Partial<IFieldSnapshot>, options?: IBaseFormulaFieldWriteOptions): boolean
changeType(type: BaseFieldType, config?: FieldConfig, options?: IBaseFormulaFieldWriteOptions): boolean
delete(): boolean
move(target: { beforeFieldId?: string; afterFieldId?: string }): boolean
```

Writing Formula config through `setConfig`, `update`, or `changeType` also requires `options.externalReferences`. Metadata-only updates to an existing Formula field do not.

## FBaseTableRecord

```typescript
getId(): string
getRecord(): IRecordSnapshot
getValue(fieldId: FieldId): BaseCellValue
getValues(): IRecordSnapshot['values']
setValue(fieldId: FieldId, value: BaseCellValue): boolean
setAttachments(fieldId: FieldId, attachments: IBaseAttachment[]): boolean
setValues(values: Record<string, BaseCellValue>, fieldKey?: BaseFieldKeyEnum): boolean
delete(): boolean
duplicate(record?: Partial<Omit<IRecordSnapshot, 'id'>>): FBaseTableRecord
setOrderKey(orderKey: string): boolean
getLinkedRecordIds(fieldId: FieldId): string[]
setLinkedRecordIds(fieldId: FieldId, recordIds: readonly string[]): boolean
addLinkedRecord(fieldId: FieldId, recordId: string): boolean
removeLinkedRecord(fieldId: FieldId, recordId: string): boolean
getParent(fieldId: FieldId): FBaseTableRecord | null
getChildren(fieldId: FieldId): FBaseTableRecord[]
getAncestors(fieldId: FieldId): FBaseTableRecord[]
getDescendants(fieldId: FieldId): FBaseTableRecord[]
setParent(fieldId: FieldId, parentRecordId: string | null, orderKey?: string): boolean
addChild(fieldId: FieldId, values: Record<FieldId, BaseCellValue>, fieldKey?: BaseFieldKeyEnum, record?: Partial<Omit<IRecordSnapshot, 'id'>>): FBaseTableRecord
```

RecordLink helpers validate target records and preserve link order. Hierarchy methods use the table's single-value, same-table Parent RecordLink field. `getHierarchyFieldId()` may return a virtual id before the first hierarchy write; `addChild()` materializes it atomically. Base hierarchies support at most five levels.

Uploading or encoding a file is the caller's responsibility. `setAttachments` stores descriptors through the undoable Base command path.

```ts
record.setAttachments(attachmentsField.getId(), [
  {
    id: uploadedFileId,
    name: 'report.pdf',
    mimeType: 'application/pdf',
    sourceType: univerAPI.Enum.ImageSourceType.UUID,
    source: uploadedFileId,
  },
])
```

## FBaseTableView

```typescript
getId(): string
getView(): IViewSnapshot
getName(): string
getType(): BaseViewType
setName(name: string): boolean
getConfig(): ViewSpecificConfig
updateConfig(patch: Partial<ViewSpecificConfig>): boolean
getConditionalColorRules(): IBaseConditionalColorRule[]
setConditionalColorRules(rules: IBaseConditionalColorRule[]): boolean
addConditionalColorRule(rule: IBaseConditionalColorRule): boolean
deleteConditionalColorRule(ruleId: string): boolean
clearConditionalColorRules(): boolean
getFilter(): IFilterConfig | null
setFilter(filter: IFilterConfig | null): boolean
getSort(): ISortConfig[]
setSort(sort: ISortConfig[]): boolean
getGroup(): IGroupConfig[]
setGroup(group: IGroupConfig[]): boolean
getFieldSettings(fieldId: string): IViewFieldSetting
getVisibleFields(): FBaseTableField[]
setFieldVisible(fieldId: string, visible: boolean): boolean
setFieldWidth(fieldId: string, width: number): boolean
moveField(fieldId: string, target: { beforeFieldId?: string; afterFieldId?: string }): boolean
move(target: { beforeViewId?: string; afterViewId?: string }): boolean
delete(): boolean
getProjection(): BaseViewProjection
```

## FBaseTableRange

```typescript
getBaseId(): string
getTableId(): string
getRange(): IRange
getRow(): number
getColumn(): number
getNumRows(): number
getNumColumns(): number
getValues(): BaseCellValue[][]
getValue(): BaseCellValue
setValue(value: BaseCellValue | IBaseCellData): boolean
setValues(values: Array<Array<BaseCellValue | IBaseCellData>>): boolean
clear(): boolean
offset(rowOffset: number, columnOffset: number, numRows?: number, numColumns?: number): FBaseTableRange
```

## Bases UI

Import `@univerjs-pro/bases-ui/facade`, then call `univerAPI.getBaseUI()`.

| Category               | Methods                                                                                                                                                                                           |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Active state           | `getActiveTableId`, `getActiveViewId`, `activateTable`, `activateView`                                                                                                                            |
| Selection and viewport | `getSelection`, `setSelection`, `scrollToRecord`, `scrollToField`                                                                                                                                 |
| Editing                | `startEditingCell`, `stopEditingCell`                                                                                                                                                             |
| Panels                 | `openLeftSidebar`, `closeLeftSidebar`, `openRightSidebar`, `closeRightSidebar`, `openRecordDetail`, `openDraftRecordDetail`, `closeRecordDetail`, `openFieldConfigPanel`, `openViewSettingsPanel` |
| People options         | `getPersonOptions`, `setPersonOptions`, `getGroupOptions`, `setGroupOptions`                                                                                                                      |

`getRenderedView()` is part of the current public class but currently returns `null`.

## Events and enums

`@univerjs-pro/bases/facade` adds table, field, record, view, cell-value, and `BeforeBaseHierarchyChange` / `BaseHierarchyChanged` events to `univerAPI.Event`. Conditional-color rule updates are reported through view changes.

The current enum Facade exposes `BaseFieldType`, `BaseViewType`, filtering and sorting enums, `BaseFieldKeyEnum`, `BaseHierarchyErrorCode`, `BaseHierarchyInvalidReason`, `BaseConditionalColorTarget`, `BaseConditionalColorOperator`, and `BaseConditionalDateMode`.

Source: 

`@univerjs-pro/bases`

, 

`@univerjs-pro/bases-ui`

## File exchange

Register the Exchange Client and Bases Exchange Client plugins and import both Facade entries. These methods require a matching conversion backend; see [Bases import/export](https://docs.univer.ai/guides/bases/features/import-export.md).

```typescript
importBaseToSnapshotAsync(file: File | string): Promise<IBaseSnapshot | undefined>
importBaseToUnitIdAsync(file: File | string): Promise<string | undefined>
exportBaseBySnapshotAsync(snapshot: IBaseSnapshot, format?: ExchangeFormat, tableId?: string): Promise<File | undefined>
exportBaseByUnitIdAsync(unitId: string, format?: ExchangeFormat, tableId?: string): Promise<File | undefined>
transformSnapshotJsonToBaseDataAsync(json: ISnapshotBlockJsonResponse): Promise<IBaseSnapshot>
transformBaseDataToSnapshotJsonAsync(baseData: IBaseSnapshot): Promise<ISnapshotBlockJson>
```

Imports accept XLSX, XLS, CSV, and TSV. Exports support XLSX (default), CSV, and TSV; specify `tableId` for single-table CSV/TSV exports. Load imported collaborative IDs with `univerAPI.getCollaboration().loadBaseAsync(unitId)`.
