# Record

> Part of the NocoDB documentation (Workflows > Scripts > API Reference). Index of all pages: https://nocodb.com/llms.txt. Any docs page is available as Markdown by adding `.md` to its URL.

URL: https://nocodb.com/docs/workflows/scripts/api-reference/record
Last updated: 2026-10-03

The NocoDBRecord object in NocoDB Scripts represents one table row and gives methods to read its cell values.

The `NocoDBRecord` object represents a single row of data in a NocoDB table. Its methods let you get and work with the cell values in that record.

## Overview

You usually get records from tables or views with query methods, for example `selectRecordsAsync()` or `selectRecordAsync()`. Each NocoDBRecord object gives access to:

* The record's unique identifier
* The record's primary display value (name)
* All cell values in the record
* Formatted string representations of cell values

Most NocoDB scripts use NocoDBRecord objects. Use them to read, change, and interpret the data in your base, with rich type support.

## Properties

| Property | Type     | Description                                                        |
| -------- | -------- | ------------------------------------------------------------------ |
| `id`     | `string` | The unique identifier for this record                              |
| `name`   | `string` | The primary display value for this record (from the display field) |

## Methods

### getCellValue

Gets the value of a specific cell in the record.

**Parameters:**

* `fieldOrFieldIdOrName` (`Field | string`): The field, field ID, or field name to get the value for

**Returns:** The value of the cell. The field type sets the format (refer to the Cell Value Types section)

**Throws:** Error if the field is not found or not included in the query

**Example:**

```javascript
// Get the Projects table
const projectsTable = base.getTable('Projects');

// Query a specific record
const projectRecord = await projectsTable.selectRecordAsync('123');

if (projectRecord) {
  // Get cell values using field names
  const projectName = projectRecord.getCellValue('Project Name');
  const dueDate = projectRecord.getCellValue('Due Date');
  const status = projectRecord.getCellValue('Status');
  
  output.text(`Project: ${projectName}`);
  output.text(`Due Date: ${dueDate}`);
  output.text(`Status: ${status}`);
  
  // Get a cell value using a field object
  const assignedToField = projectsTable.getField('Assigned To');
  const assignedTo = projectRecord.getCellValue(assignedToField);
  
  if (assignedTo) {
    output.text(`Assigned To: ${assignedTo.name}`);
  } else {
    output.text('This project is unassigned.');
  }
}
```

### getCellValueAsString

Gets a cell value as a string. The formatting depends on the field type.

**Parameters:**

* `fieldOrFieldIdOrName` (`Field | string`): The field, field ID, or field name to get the value for

**Returns:** `string`: The cell value as a string, with the correct formatting for the field type

**Throws:** Error if the field is not found or not included in the query

**Note:** This method formats all field types, including currency, dates, durations, percentages, and more.

**Example:**

```javascript
// Get the Invoices table
const invoicesTable = base.getTable('Invoices');

// Query a specific record
const invoiceRecord = await invoicesTable.selectRecordAsync('123');

if (invoiceRecord) {
  // Get formatted string values
  const invoiceNumber = invoiceRecord.getCellValueAsString('Invoice Number');
  const amount = invoiceRecord.getCellValueAsString('Amount'); // Formatted as currency
  const date = invoiceRecord.getCellValueAsString('Date'); // Formatted as date
  const isPaid = invoiceRecord.getCellValueAsString('Paid'); // "Checked" or "Unchecked"
  const attachments = invoiceRecord.getCellValueAsString('Attachments'); // Comma-separated file names
  
  // Output the formatted values
  output.text(`Invoice: ${invoiceNumber}`);
  output.text(`Amount: ${amount}`);
  output.text(`Date: ${date}`);
  output.text(`Paid: ${isPaid}`);
  output.text(`Attachments: ${attachments}`);
}
```

## Cell Value Types

When you use `getCellValue()`, each field type returns values in a specific format. This section shows the format for the most common field types:

### Text Fields

```javascript
// Single Line Text & Long Text
const title = record.getCellValue('Title'); // string or null
```

### Number Fields

```javascript
// Number, Decimal, Currency, Percent
const amount = record.getCellValue('Amount'); // number or null
const quantity = record.getCellValue('Quantity'); // number or null
const price = record.getCellValue('Price'); // number or null
const discount = record.getCellValue('Discount'); // number or null (without % sign)
```

### Boolean Fields

```javascript
// Checkbox
const isCompleted = record.getCellValue('Completed'); // boolean or null
```

### Date and Time Fields

```javascript
// Date
const dueDate = record.getCellValue('Due Date'); // string in ISO format or null
// e.g., "2023-08-15"

// DateTime
const createdAt = record.getCellValue('Created At'); // string in ISO format or null
// e.g., "2023-08-15T14:30:00.000Z"

// Time
const startTime = record.getCellValue('Start Time'); // string in ISO format or null
// e.g., "14:30:00.000"
```

### Selection Fields

```javascript
// Single Select
const status = record.getCellValue('Status'); // string or null
// e.g., "In Progress"

// Multi Select
const tags = record.getCellValue('Tags'); // array of strings or empty array
// e.g., ["Urgent", "Bug"]
```

### Relationship Fields

```javascript
// LinkToAnotherRecord (one to one / belongs to relationship)
const project = record.getCellValue('Project'); // NocoDBRecord object or null
if (project) {
  output.text(`Project ID: ${project.id}`);
  output.text(`Project Name: ${project.name}`);
}

// LinkToAnotherRecord (many-to-many / has-many relationship)
const team = record.getCellValue('Team Members'); // RecordQueryResult object or null
while (team.hasMoreRecords) {
  await team.loadMoreRecords();
}

output.text(`Team members: ${team.records.length}`);

// Links (new field type for relationships)
const linkedProjects = record.getCellValue('Related Projects');
// For many-to-many/has-many: returns RecordQueryResult object or null
// For belongs-to/one-to-one: returns NocoDBRecord object or null
```

### Attachment Field

```javascript
// Attachment
const documents = record.getCellValue('Documents'); // Array of attachment objects or empty array

/*
Each attachment object has:
{
  url: string,
  title: string,
  mimetype: string,
  size: number,
  signedUrl?: string,
  thumbnails?: {
    tiny: { signedUrl: string },
    small: { signedUrl: string },
    card_cover: { signedUrl: string }
  }
}
*/

if (documents && documents.length > 0) {
  for (const doc of documents) {
    output.text(`File: ${doc.title}`);
    output.text(`Type: ${doc.mimetype}`);
    output.text(`Size: ${doc.size} bytes`);
    output.text(`URL: ${doc.url}`);
  }
}
```

### User Field

```javascript
// User (single)
const assignee = record.getCellValue('Assigned To'); // Collaborator object or null

if (assignee) {
  output.text(`Assignee ID: ${assignee.id}`);
  output.text(`Assignee Name: ${assignee.name}`);
  output.text(`Assignee Email: ${assignee.email}`);
}

// User (multiple)
const reviewers = record.getCellValue('Reviewers'); // Array of Collaborator objects or empty array

if (reviewers && reviewers.length > 0) {
  for (const reviewer of reviewers) {
    output.text(`Reviewer ID: ${reviewer.id}`);
    output.text(`Reviewer Name: ${reviewer.name}`);
    output.text(`Reviewer Email: ${reviewer.email}`);
  }
}
```

### Formula Field

```javascript
// Formula fields return a value of the appropriate type based on the formula's output type
const fullName = record.getCellValue('Full Name'); // string or null
const age = record.getCellValue('Age'); // number or null
const isAdult = record.getCellValue('Is Adult'); // boolean or null
```

### Lookup Field

```javascript
// Lookup fields return values of the type that is being looked up
const managerName = record.getCellValue('Manager Name'); // string or null
const departmentSize = record.getCellValue('Department Size'); // number or null

// Lookup to multiple values
const teamEmails = record.getCellValue('Team Emails'); // Array of values or empty array
```

### Rollup Field

```javascript
// Rollup fields return values based on the rollup function and field type
const totalHours = record.getCellValue('Total Hours'); // number or null
const averageScore = record.getCellValue('Average Score'); // number or null
const taskCount = record.getCellValue('Task Count'); // number or null
```

## Working with Records

### Reading Record Data

```javascript
// Get the Tasks table
const tasksTable = base.getTable('Tasks');

// Get a specific record
const taskRecord = await tasksTable.selectRecordAsync('123', {
  fields: ['Task Name', 'Description', 'Status', 'Due Date', 'Assigned To', 'Priority']
});

if (taskRecord) {
  // Read basic properties
  output.text(`Record ID: ${taskRecord.id}`);
  output.text(`Primary Value: ${taskRecord.name}`);
  
  // Read values using getCellValue
  const taskName = taskRecord.getCellValue('Task Name');
  const description = taskRecord.getCellValue('Description');
  const status = taskRecord.getCellValue('Status');
  const dueDate = taskRecord.getCellValue('Due Date');
  const assignedTo = taskRecord.getCellValue('Assigned To');
  const priority = taskRecord.getCellValue('Priority');
  
  // Display the task information
  output.markdown(`# Task: ${taskName}`);
  output.text(`Description: ${description || 'No description provided'}`);
  output.text(`Status: ${status || 'Not set'}`);
  output.text(`Due Date: ${dueDate ? new Date(dueDate).toLocaleDateString() : 'No due date'}`);
  
  if (assignedTo) {
    output.text(`Assigned To: ${assignedTo.name} (${assignedTo.email})`);
  } else {
    output.text('This task is unassigned.');
  }
  
  output.text(`Priority: ${priority || 'Not set'}`);
}
```

### Comparing Records

```javascript
// Get the Employees table
const employeesTable = base.getTable('Employees');

// Get two employee records
const employee1 = await employeesTable.selectRecordAsync('123');
const employee2 = await employeesTable.selectRecordAsync('456');

if (employee1 && employee2) {
  // Compare salary values
  const salary1 = employee1.getCellValue('Salary') || 0;
  const salary2 = employee2.getCellValue('Salary') || 0;
  
  // Compare departments
  const dept1 = employee1.getCellValue('Department');
  const dept2 = employee2.getCellValue('Department');
  
  // Compare hire dates
  const hireDate1 = employee1.getCellValue('Hire Date');
  const hireDate2 = employee2.getCellValue('Hire Date');
  
  // Output comparison
  output.markdown(`# Employee Comparison`);
  output.markdown(`## ${employee1.getCellValue('Name')} vs. ${employee2.getCellValue('Name')}`);
  
  output.text(`Salary: $${salary1.toLocaleString()} vs. $${salary2.toLocaleString()}`);
  output.text(`Department: ${dept1} vs. ${dept2}`);
  
  if (hireDate1 && hireDate2) {
    const date1 = new Date(hireDate1);
    const date2 = new Date(hireDate2);
    const seniorityDiff = Math.floor((date2 - date1) / (1000 * 60 * 60 * 24));
    
    if (seniorityDiff > 0) {
      output.text(`${employee1.getCellValue('Name')} has been with the company ${seniorityDiff} days longer.`);
    } else if (seniorityDiff < 0) {
      output.text(`${employee2.getCellValue('Name')} has been with the company ${Math.abs(seniorityDiff)} days longer.`);
    } else {
      output.text('Both employees were hired on the same day.');
    }
  }
}
```

### Working with Linked Records

```javascript
// Get the Projects and Tasks tables
const projectsTable = base.getTable('Projects');
const tasksTable = base.getTable('Tasks');

// Get a project record with its linked tasks
const projectRecord = await projectsTable.selectRecordAsync('25', {
  fields: ['Project Name', 'Description', 'Status', 'Tasks']
});
 
if (projectRecord) {
  const projectName = projectRecord.getCellValue('Project Name');
  const tasks = projectRecord.getCellValue('Tasks') || [];

  while(tasks.hasMoreRecords) {
    await tasks.loadMoreRecords()
  }
  
  output.markdown(`# Project: ${projectName}`);
  output.text(`Status: ${projectRecord.getCellValue('Status')}`);
  output.text(`Number of Tasks: ${tasks.records.length}`);
  
  if (tasks.records.length > 0) {
    // Direct access to linked record information
    output.markdown('## Task Summary');
    
    for (const task of tasks.records) {
      output.text(`- ${task.name}`);
    }
    
    // For detailed task information, we need to query each task
    output.markdown('## Detailed Task Information');
    
    // Get all task IDs
    const taskIds = tasks.recordIds
    
    // Query the tasks with additional fields
    const taskRecords = await tasksTable.selectRecordsAsync({
      fields: ['Task Name', 'Status', 'Due Date', 'Assigned To'],
      recordIds: taskIds
    });
    
    // Process each task with full details
    for (const taskRecord of taskRecords.records) {
      const taskName = taskRecord.getCellValue('Task Name');
      const status = taskRecord.getCellValue('Status');
      const dueDate = taskRecord.getCellValue('Due Date');
      const assignedTo = taskRecord.getCellValue('Assigned To');
      
      output.markdown(`### ${taskName}`);
      output.text(`Status: ${status || 'Not set'}`);
      output.text(`Due Date: ${dueDate ? new Date(dueDate).toLocaleDateString() : 'No due date'}`);
      output.text(`Assigned To: ${assignedTo ? assignedTo.name : 'Unassigned'}`);
    }
  }
}
```

### Using Record Values in Calculations

```javascript
// Get the Sales table
const salesTable = base.getTable('Sales');

// Query sales records for a specific period
const salesRecords = await salesTable.selectRecordsAsync({
  fields: ['Date', 'Product', 'Quantity', 'Unit Price', 'Total']
});

while(salesRecords.hasMoreRecords) {
  await salesRecords.loadMoreRecords()
}

// Perform calculations with record values
let totalSales = 0;
let totalQuantity = 0;
let highestSale = { amount: 0, product: null, date: null };

for (const record of salesRecords.records) {
  const quantity = record.getCellValue('Quantity') || 0;
  const total = record.getCellValue('Total') || 0;
  
  // Update totals
  totalSales += total;
  totalQuantity += quantity;
  
  // Check if this is the highest sale
  if (total > highestSale.amount) {
    highestSale = {
      amount: total,
      product: record.getCellValue('Product'),
      date: record.getCellValue('Date')
    };
  }
}

// Calculate average sale value
const averageSale = salesRecords.records.length > 0 
  ? totalSales / salesRecords.records.length 
  : 0;

// Output the results
output.markdown('# Sales Analysis');
output.text(`Total Sales: $${totalSales.toLocaleString()}`);
output.text(`Total Quantity: ${totalQuantity.toLocaleString()} units`);
output.text(`Average Sale: $${averageSale.toFixed(2)}`);

if (highestSale.product) {
  output.markdown('## Highest Sale');
  output.text(`Product: ${highestSale.product}`);
  output.text(`Amount: $${highestSale.amount.toLocaleString()}`);
  output.text(`Date: ${highestSale.date ? new Date(highestSale.date).toLocaleDateString() : 'Unknown'}`);
}
```

### Complex Record Processing

```javascript
// Get the Inventory table
const inventoryTable = base.getTable('Inventory');

// Get all inventory records
const inventoryRecords = await inventoryTable.selectRecordsAsync({
  fields: ['Item Name', 'Category', 'Quantity', 'Reorder Level', 'Supplier', 'Price']
});

// Identify items that need to be reordered
const reorderItems = [];
const lowStockItems = [];
const outOfStockItems = [];

for (const record of inventoryRecords.records) {
  const itemName = record.getCellValue('Item Name');
  const quantity = record.getCellValue('Quantity') || 0;
  const reorderLevel = record.getCellValue('Reorder Level') || 0;
  
  // Add to appropriate lists
  if (quantity === 0) {
    outOfStockItems.push({
      id: record.id,
      name: itemName,
      category: record.getCellValue('Category'),
      supplier: record.getCellValue('Supplier'),
      price: record.getCellValue('Price')
    });
  } else if (quantity <= reorderLevel) {
    reorderItems.push({
      id: record.id,
      name: itemName,
      category: record.getCellValue('Category'),
      currentQuantity: quantity,
      reorderLevel: reorderLevel,
      supplier: record.getCellValue('Supplier'),
      price: record.getCellValue('Price')
    });
  } else if (quantity <= reorderLevel * 1.2) {
    // Items at 120% or less of reorder level are considered low stock
    lowStockItems.push({
      id: record.id,
      name: itemName,
      category: record.getCellValue('Category'),
      currentQuantity: quantity,
      reorderLevel: reorderLevel
    });
  }
}

// Group reorder items by supplier
const itemsBySupplier = {};

for (const item of reorderItems) {
  const supplier = item.supplier || 'Unknown Supplier';
  
  if (!itemsBySupplier[supplier]) {
    itemsBySupplier[supplier] = [];
  }
  
  itemsBySupplier[supplier].push(item);
}

// Output the inventory report
output.markdown('# Inventory Report');

if (outOfStockItems.length > 0) {
  output.markdown('## Out of Stock Items');
  output.table(outOfStockItems);
}

if (reorderItems.length > 0) {
  output.markdown('## Items to Reorder');
  output.table(reorderItems);
  
  output.markdown('## Reorder by Supplier');
  for (const [supplier, items] of Object.entries(itemsBySupplier)) {
    output.markdown(`### ${supplier}`);
    
    // Calculate order totals
    const orderTotal = items.reduce((sum, item) => sum + (item.price || 0), 0);
    
    output.table(items);
    output.text(`Order Total: $${orderTotal.toLocaleString()}`);
  }
}

if (lowStockItems.length > 0) {
  output.markdown('## Low Stock Items');
  output.table(lowStockItems);
}
```

## Best Practices

1. **Check for null values**: Field values can be null or undefined. Always handle this case with default values or conditional logic.

2. **Use appropriate methods**: Use `getCellValue()` when you need the actual value for calculations or logic. Use `getCellValueAsString()` to show the value.

3. **Handle linked records properly**: Linked records from `getCellValue()` contain only minimal information (id and name). For detailed information, query the linked records from their table.

4. **Field parameter consistency**: For consistency, use field names (strings). Use field objects only if you need their special functionality.

5. **Error handling**: Put record operations in try-catch blocks to handle possible errors gracefully.

6. **Update records with care**: When you update records, keep the existing values of fields that you do not want to change.

## Related

* [Base](/docs/workflows/scripts/api-reference/base)
* [Table](/docs/workflows/scripts/api-reference/table)
* [Field](/docs/workflows/scripts/api-reference/field)
* [RecordQueryResult](/docs/workflows/scripts/api-reference/record-query-result)

---

## Related pages

- [Base](https://nocodb.com/docs/workflows/scripts/api-reference/base.md): The base object in NocoDB Scripts gives access to the tables and collaborators of the current base.
- [Cursor](https://nocodb.com/docs/workflows/scripts/api-reference/cursor.md): The cursor object in NocoDB Scripts tells a script which base, table, view and row are active.
- [Table](https://nocodb.com/docs/workflows/scripts/api-reference/table.md): The Table object in NocoDB Scripts represents a table and gives methods to query, create, update, and delete its records.
- [View](https://nocodb.com/docs/workflows/scripts/api-reference/view.md): The View object in NocoDB Scripts represents a view of a table and lets you query its records.
- [Field](https://nocodb.com/docs/workflows/scripts/api-reference/field.md): The Field object in NocoDB Scripts gives access to the configuration of a table column, and the field types and their cell values.
- [RecordQueryResult](https://nocodb.com/docs/workflows/scripts/api-reference/record-query-result.md): The RecordQueryResult object in NocoDB Scripts holds the records from a query and supports pagination.
- [Session](https://nocodb.com/docs/workflows/scripts/api-reference/session.md): The session object in NocoDB Scripts gives information about the user who runs the script.
- [Collaborator](https://nocodb.com/docs/workflows/scripts/api-reference/collaborator.md): The Collaborator object in NocoDB Scripts holds the ID, name and email of a user who has access to a base.
