Multi-Line Text Field
Store longer free-form text — descriptions, notes, logs — on a record with the TEXT_MULTI custom field type.
A multi-line text field stores free-form text that can span several lines, such as descriptions, notes, or logs. It is the TEXT_MULTI value of the CustomFieldType enum. Custom fields are CustomField objects scoped to a workspace (a Workspace in the API); records are Record objects.
TEXT_MULTI and TEXT_SINGLE store and validate text the same way — the difference is the editor the app renders (a multi-line textarea versus a single-line input). Choose TEXT_MULTI when you expect line breaks.
Create
Create the field with createCustomField. The workspace is taken from the blue-workspace-id header — there is no projectId argument.
mutation CreateTextMultiField {
createCustomField(input: { name: "Notes", type: TEXT_MULTI }) {
id
name
type
}
}Pass description to show help text under the field in the app:
mutation CreateDetailedTextMultiField {
createCustomField(
input: {
name: "Notes"
type: TEXT_MULTI
description: "Free-form notes and observations about this record."
}
) {
id
name
type
description
}
}CreateCustomFieldInput
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String! | Yes | Display name of the field. |
type | CustomFieldType! | Yes | Must be TEXT_MULTI. |
description | String | No | Help text shown under the field in the app. |
A successful call returns the created CustomField:
{
"data": {
"createCustomField": {
"id": "clm4n8qwx000008l0g4oxdqn7",
"name": "Notes",
"type": "TEXT_MULTI"
}
}
}Set a value
Write text to a record with setRecordCustomField, using the text argument. The mutation returns Boolean! — true on success — so it takes no selection set.
mutation SetTextMultiValue {
setRecordCustomField(
input: {
todoId: "todo_123"
customFieldId: "field_123"
text: "Kickoff call done.\n\nNext: send proposal by Friday."
}
)
}{ "data": { "setRecordCustomField": true } }SetRecordCustomFieldInput
| Parameter | Type | Required | Description |
|---|---|---|---|
todoId | String! | Yes | ID of the record to write to. |
customFieldId | String! | Yes | ID of the TEXT_MULTI field. |
text | String | No | The text to store. Newlines are preserved. Omit to clear the value. |
You can also set the value when creating a record. CreateRecordInput.customFields takes CreateRecordInputCustomField entries ({ customFieldId, value }), where value is the text passed as a string:
mutation CreateRecordWithNotes {
createRecord(
input: {
title: "Acme onboarding"
todoListId: "list_123"
customFields: [
{
customFieldId: "field_123"
value: "Kickoff call done.\n\nNext: send proposal by Friday."
}
]
}
) {
id
title
}
}Read a value
Record.customFields returns CustomField objects directly — there is no junction wrapper type. Read the value on each element. For TEXT_MULTI, the value field resolves to the stored string (the same string is also on the text field).
query GetRecordNotes {
recordQueries {
todos(filter: { companyIds: ["company_123"], todoIds: ["todo_123"] }) {
items {
id
title
customFields {
name
type
text
value
}
}
}
}
}{
"data": {
"recordQueries": {
"todos": {
"items": [
{
"id": "clm4n8qwx000008l0g4oxdqn7",
"title": "Acme onboarding",
"customFields": [
{
"name": "Notes",
"type": "TEXT_MULTI",
"text": "Kickoff call done.\n\nNext: send proposal by Friday.",
"value": "Kickoff call done.\n\nNext: send proposal by Friday."
}
]
}
]
}
}
}
}CustomField (record context)
When a CustomField is read through Record.customFields, these fields carry the record’s value:
| Field | Type | Description |
|---|---|---|
name | String! | The field’s display name. |
type | CustomFieldType! | TEXT_MULTI for this field. |
text | String | The stored text, including line breaks. |
value | JSON | The resolved value — the plain text string for TEXT_MULTI fields. |
Notes
- Text is stored verbatim through the API: no trimming, no length limit beyond the column’s storage capacity, and full Unicode support. Forms applied to the field may trim whitespace and enforce required-ness; the direct API does not.
valueis only populated when theCustomFieldis read in a record context (throughRecord.customFields). On a bare field definition fetched from thecustomFieldsquery it isnull.TEXT_MULTIandTEXT_SINGLEshare storage and validation; this parity is current behavior, not a guaranteed contract.
Errors
| Code | When |
|---|---|
CUSTOM_FIELD_NOT_FOUND | The customFieldId does not exist or is not in a workspace you can access. |
TODO_NOT_FOUND | The todoId does not exist or is not in a workspace you can access. |
CUSTOM_FIELD_LIMIT | The workspace has reached its 30 custom-field limit (raise it by upgrading to Enterprise). |
FORBIDDEN | Your role cannot perform the action — VIEW_ONLY and COMMENT_ONLY roles cannot set field values. |
Related
- Single-Line Text Field — short, single-line values.
- Email Field — email addresses.
- URL Field — links.
- Set custom field values — the
setRecordCustomFieldreference. - Custom Fields overview — types, access control, and operations.