--- title: "Build a Bulk Update Module" slug: "build-a-bulk-update-module" description: "Build a module to upload CSV files and bulk-update Data Model records with ease, ensuring efficient data management and job status tracking." status: "update" updated: 2026-10-13T15:33:43Z published: 2026-10-13T15:33:43Z canonical: "docs.unqork.io/build-a-bulk-update-module" --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.unqork.io/llms.txt > Use this file to discover all available pages before exploring further. # Build a Bulk Update Module This guide walks you through building a UI module that lets Creators upload a CSV file and bulk-update records in an existing Data Model. From a single button click, the module generates an upload URL, uploads the file, runs the update, and checks job status. [Download the example module bundle](https://cdn.us.document360.io/15548f06-2fba-434c-b0c1-5df88317dbd7/Images/Setting/bulk-update-poc.uqbundle?sv=2026-02-06&spr=https&st=2026-10-27T23%3A17%3A22Z&se=2026-10-28T00%3A17%3A22Z&sr=c&sp=r&sig=yaxysQFK9v%2BXNEKWOWUXzJkKii6zIaYLRWqeNIDHkOY%3D) to use as a starting point. After importing, replace every placeholder before using the module: | Placeholder | Appears in | Replace with. | | --- | --- | --- | | `REPLACE_WITH_DATA_MODEL_ID` | `pluginBulkUpdateRecord` | The resource ID of the target Data Model. | > [!NOTE] > BDO Update only works with Data Model records. It does not support module submission records. ## Prerequisites - Creator or Express Administrator access to your workspace. - A target Data Model containing the records to update. - A CSV file with the updated values; each row must include the field used as the match key (typically `_id`). - Familiarity with the **Plug-In**, **Decisions**, and **File** components. ## Module Overview Organize the module into three field groups: one for initialization logic, one for the Creator-facing UI, and one for the backend Plug-In component sequence. | Name | Key | Component | Purpose | | --- | --- | --- | --- | | On-Load Initializer | `initOnload` | Initializer | Triggers on page load. | | Refresh Button | `btnRefresh` | Button | Lets the Creator check job status manually; enabled when a job is running. | | File Upload | `fileUpload` | File | Accepts the CSV containing the updated records. | | Enable Button Rule | `ruleFileUpload` | Decisions | Enables `btnBulkUpdate` when a file is selected. | | Update Button | `btnBulkUpdate` | Button | Starts the upload and update sequence. | | Success Initializer | `initSuccess` | Initializer | Sets the response field to indicate success. | | Error Initializer | `initError` | Initializer | Sets the response field to indicate failure. | | Generate Upload Link | `pluginGenerateUploadLink` | Plug-In | Calls the Upload-Link endpoint to get a pre-signed URL. | | Upload File | `pluginUploadFile` | Plug-In | Posts the file bytes to the upload URL. | | Update Records | `pluginBulkUpdateRecord` | Plug-In | Calls the Update endpoint with the returned file key. | | Get Job Status | `pluginGetJobDetails` | Plug-In | Checks update progress using the job ID. | | Check Status Rule | `ruleCheckStatus` | Decisions | Shows a status message and resets the form when complete. | > [!NOTE] > The example Property IDs in this guide use a `plugin` prefix (for example, `pluginExport`) for clarity. The platform default for Plug-In components is `plug` — see [Property ID Naming Conventions](/unqorkai/docs/property-id-naming-conventions). > **How to read settings tables** > > > The tables below describe each configurable option as it shows in the platform. Values are formatted as follows: `inline code` — a value to type exactly as shown | **Bold** — a value selected from a drop-down, radio button, tab, or choice chip | **ON**/**OFF** — toggle state | ✓ — checkbox checked | ☐ — checkbox unchecked ## Set Up the Field Groups Create three field groups in the module to keep components organized. | Field Group | Contains | | --- | --- | | `fgOnLoad` | The on-load Initializer that fires when the page renders. | | `fgUI` | The buttons, file component, and enable rule the Creator interacts with. | | `fgConfig` | All update Plug-In components, status logic, Initializers, and hidden fields. | ## Create the Supporting Fields Add the following fields to `fgConfig`. These fields carry data between components throughout the upload and update sequence. | Property ID | Component | Default | Purpose | | --- | --- | --- | --- | | `uploadLink` | Hidden | — | Stores the pre-signed upload URL returned by `pluginGenerateUploadLink`. | | `fileKey` | Hidden | — | Stores the Unqork file key returned after the file upload. | | `jobId` | Hidden | — | Stores the update job ID returned by `pluginBulkUpdateRecord`. | | `status` | Hidden | — | Stores the current job status returned by `pluginGetJobDetails`. | | `response` | Hidden | — | Set to `Success` by `initSuccess` or `Fail` by `initError`. | ## Configure `initOnload` The `initOnload` Initializer component fires when the module first loads and serves as the module's entry point. It has no outputs and no connections to other components. 1. Add an **Initializer** component to `fgOnLoad`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `initOnload` | | Trigger Type | **New Submission** | ## Configure `fileUpload` The `fileUpload` File component captures the CSV the Creator selects. After a file is chosen, it triggers the `ruleFileUpload` Decisions component to enable the update button. 1. Add a **File** component to `fgUI`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `fileUpload` | | Label | `Upload File` | | Accepted File Types | `.csv` | 3. Under **Triggers**, set the **Post Upload** drop-down to `ruleFileUpload`. ## Configure `ruleFileUpload` The `ruleFileUpload` Decisions component checks whether a file has been selected and enables the `btnBulkUpdate` Button component when one is present. It is triggered by the `fileUpload` File component after each file selection. 1. Add a **Decisions** component to `fgUI` after `fileUpload`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `ruleFileUpload` | | Trigger Type | **Manual** | 3. Configure the **Inputs**: | # | Property ID | Alias | Type | | --- | --- | --- | --- | | 1 | `fileUpload` | `A` | Exact | 4. Configure the **Outputs**: | # | Property ID | Type | | --- | --- | --- | | 1 | `btnBulkUpdate` | Disabled | 5. Add one row in the **Decision** grid: | `fileUpload` | `btnBulkUpdate_disabled` | | --- | --- | | (wildcard) | `=IF(LEN(A)>0,'no','yes')` | ## Configure `btnBulkUpdate` The `btnBulkUpdate` Button component starts the upload and update sequence. It starts disabled and is enabled by the `ruleFileUpload` Decisions component once a file is selected. On successful validation, it triggers the `pluginGenerateUploadLink` Plug-In component. 1. Add a **Button** component to `fgUI` after `ruleFileUpload`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `btnBulkUpdate` | | Label | `Bulk Update` | | Action | **Validate** | | Initial State | **Disabled** | 3. Under **Triggers**, set the **On Validation Success** drop-down to `pluginGenerateUploadLink`. ## Configure `btnRefresh` The `btnRefresh` Button component lets the Creator manually re-check job status. It triggers the `pluginGetJobDetails` Plug-In component on click, and the `ruleCheckStatus` Decisions component enables it once a job is running. It starts disabled. 1. Add a **Button** component to `fgUI` above `fileUpload`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `btnRefresh` | | Label | `Refresh` | | Action | **Event** | | Initial State | **Disabled** | 3. Under **Triggers**, set the **On Click** drop-down to `pluginGetJobDetails`. ## Configure `initSuccess` The `initSuccess` Initializer component sets the `response` field to `Success` when the update completes without errors. 1. Add an **Initializer** component to `fgConfig`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `initSuccess` | | Trigger Type | **Manual** | 3. Configure the **Outputs**: | # | Property ID | Type | Value | | --- | --- | --- | --- | | 1 | `response` | Value | `Success` | ## Configure `initError` The `initError` Initializer component sets the `response` field to `Fail` when something goes wrong. All Plug-In components in `fgConfig` reference it as their error handler. 1. Add an **Initializer** component to `fgConfig` after `initSuccess`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `initError` | | Trigger Type | **Manual** | 3. Configure the **Outputs**: | # | Property ID | Type | Value | | --- | --- | --- | --- | | 1 | `response` | Value | `Fail` | ## Configure `pluginGenerateUploadLink` The `pluginGenerateUploadLink` Plug-In component gets a pre-signed URL for uploading the file to the Unqork Cloud. It is triggered by the `btnBulkUpdate` Button component. On success, it triggers the `pluginUploadFile` Plug-In component. 1. Add a **Plug-In** component to `fgConfig`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `pluginGenerateUploadLink` | | Trigger Type | **Manual** | | Endpoint URL | `https://{environment}.unqork.io/fbu/uapi/bulkOperations/uploadLink` | | Method | **POST** | 3. No Inputs are required for this endpoint. 4. Configure the **Outputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `uploadLink` | `uploadLink` | 5. Under **Triggers**, set the **Post Trigger** drop-down to `pluginUploadFile` and the **Error Handler** drop-down to `initError`. ## Configure `pluginUploadFile` The `pluginUploadFile` Plug-In component posts the file bytes to the pre-signed URL using multipart/form-data. It is triggered by the `pluginGenerateUploadLink` Plug-In component. On success, it triggers the `pluginBulkUpdateRecord` Plug-In component. The endpoint URL is built dynamically from the `uploadLink` field. 1. Add a **Plug-In** component to `fgConfig` after `pluginGenerateUploadLink`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `pluginUploadFile` | | Trigger Type | **Manual** | | Endpoint URL | `/api{{data.uploadLink}}` | | Method | **POST** | | Multipart | **ON** | 3. Configure the **Headers**: | # | Property ID | Value | | --- | --- | --- | | 1 | `Connect-Type` | `multipart/form-data` | 4. Configure the **Inputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `file` | `fileUpload[0]['url']` | > [!NOTE] > Enable **Resolve Base64** on the `file` input so the platform sends the file bytes rather than the base64 string. 5. Configure the **Outputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `fileKey` | `fileKey` | 6. Under **Triggers**, set the **Post Trigger** drop-down to `pluginBulkUpdateRecord` and the **Error Handler** drop-down to `initError`. ## Configure `pluginBulkUpdateRecord` The `pluginBulkUpdateRecord` Plug-In component calls the Update endpoint using the `fileKey` from the upload step. It is triggered by the `pluginUploadFile` Plug-In component. On success, it triggers the `pluginGetJobDetails` Plug-In component to begin polling. 1. Add a **Plug-In** component to `fgConfig` after `pluginUploadFile`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `pluginBulkUpdateRecord` | | Trigger Type | **Manual** | | Endpoint URL | `https://{environment}.unqork.io/fbu/uapi/bulkOperations/update` | | Method | | 3. Configure the **Inputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `resourceId` | `'REPLACE_WITH_DATA_MODEL_ID'` | | 2 | `fallbackRecordOwner` | `currentUser['email']` | | 3 | `fileFormat` | `'CSV'` | | 4 | `fileLocation` | `fileKey` | | 5 | `name` | `fileUpload[0]['name']` | | 6 | `storeInData` | `'true'` | | 7 | `uniqueKey` | `'_id'` (or the field used to match existing records) | > [!NOTE] > To insert new records when no match is found, add an eighth input mapping `upsert` to `'true'`. When `upsert` is `false` (the default), the operation skips records without a matching key. 4. Configure the **Outputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `status` | `data.status` | | 2 | `jobId` | `id` | 5. Under **Triggers**, set the **Post Trigger** drop-down to `pluginGetJobDetails` and the **Error Handler** drop-down to `initError`. ## Configure `pluginGetJobDetails` The `pluginGetJobDetails` Plug-In component checks the status of the update job. It is triggered by the `pluginBulkUpdateRecord` Plug-In component on success, and by the `btnRefresh` Button component when the Creator clicks it manually. On completion, it triggers the `ruleCheckStatus` Decisions component. 1. Add a **Plug-In** component to `fgConfig` after `pluginBulkUpdateRecord`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `pluginGetJobDetails` | | Trigger Type | **Manual** | | Endpoint URL | `https://{environment}.unqork.io/fbu/uapi/bulkOperations/jobs/{{data.jobId}}` | | Method | | 3. Configure the **Outputs**: | # | Property ID | Value | | --- | --- | --- | | 1 | `status` | `data.status` | 4. Under **Triggers**, set the **Post Trigger** drop-down to `ruleCheckStatus`. > [!NOTE] > All BDO endpoints in this module use the `bulkOperations` (camelCase, no hyphen). ## Configure `ruleCheckStatus` The `ruleCheckStatus` Decisions component reads the job status written by the `pluginGetJobDetails` Plug-In component, displays a pop-up message, and enables the `btnRefresh` Button component while the job is running. When the job reaches `completed`, it clears and resets `fgUI` so the Creator can start another update. 1. Add a **Decisions** component to `fgConfig` after `pluginGetJobDetails`. 2. Configure the following settings: | Setting | Value | | --- | --- | | Property ID | `ruleCheckStatus` | | Trigger Type | **Manual** | 3. Configure the **Inputs**: | # | Property ID | Alias | Type | | --- | --- | --- | --- | | 1 | `jobId` | `A` | Exact | | 2 | `status` | | Exact | 4. Configure the **Outputs**: | # | Property ID | Type | | --- | --- | --- | | 1 | `btnRefresh` | Disabled | | 2 | `fgUI` | Pop Message | | 3 | `fgUI` | Multi | 5. Add one row per job status in the **Decision** grid: | Status | `btnRefresh_disabled` | `fgUI_popMessage` | `fgUI_multi` | | --- | --- | --- | --- | | `created` | `=IF(LEN(A)>0,'no','yes')` | `Update started.` | | | `inProgress` | `=IF(LEN(A)>0,'no','yes')` | `Update in progress.` | | | `completed` | `=IF(LEN(A)>0,'no','yes')` | `Update complete.` | `clear.reset` | | `partiallyCompleted` | `=IF(LEN(A)>0,'no','yes')` | `Update partially complete.` | | | `canceled` | `=IF(LEN(A)>0,'no','yes')` | `Update canceled.` | | | `failed` | `=IF(LEN(A)>0,'no','yes')` | `Update failed.` | | The formula in the disabled column uses `A` (the `jobId` alias). The `clear.reset` multi-action on `completed` clears `fgUI` and resets the form for the next update. ## Prepare the CSV The bulk update CSV differs from a bulk upload CSV. Each row must include the value used as the match key so the platform can locate the record to update. By default, this is the `_id` column. The CSV requires the following columns: | Column | Required | Description | | --- | --- | --- | | `_id` | Yes (or your chosen `uniqueKey`) | The Unqork submission ID of the record to update (24-character hexadecimal string). | | Any Data Model field | Yes (at least one) | Column headers must match the Data Model field keys exactly; only the columns present in the file are updated. | A complete CSV looks like this: ```csv _id,firstName,lastName,email 6abeb2b1277a9f5cd3918aca,Todd,Smith,todd.smith@example.com 6abeb2b1277a9f5cd3918acb,Aisha,Patel,aisha.patel@example.com 6abeb2b1277a9f5cd3918acc,Liam,Nguyen,liam.nguyen@example.com ``` > [!NOTE] > To find the `_id` values for records you want to update, you can either: > > > - Export the records using the [Build a Bulk Download Module](/unqorkai/docs/build-a-bulk-download-module) guide, then edit the downloaded file and re-upload it here. > - Open the **Explorer** tab in the platform, navigate to **Utilities** > **Record Collections** > **Modules** > your module name, and copy the `_id` from the record you want to update. ## Test the Module 1. Open the module in **Preview**. 2. Select a CSV file formatted as described in [Prepare the CSV](/unqorkai/docs/build-a-bulk-update-module#prepare-the-csv). The **Bulk Update** button enables when a file is present. 3. Click **Bulk Update**. 4. Click **Refresh** until the pop-up message reads `Update complete.` 5. Open the submission using the platform's submission inspection method. See [Debugger](/unqorkai/docs/api-debugger) for how to access submission data from Express View. 6. Confirm the `jobId` and `status` fields contain the expected values. 7. Navigate to the target Data Model's Record Collection to verify the updated records reflect the values from the CSV. --- **Changelog** | Date | Change. | | --- | --- | | 2026-10-05 | Added Prepare the CSV section explaining column structure and the `_id` match key requirement. | | 2026-10-05 | Updated bundle from tested POC; corrected `pluginBulkUpdateRecord` input from `dataModelOrModuleId` to `resourceId`. | | 2026-10-05 | Full restructure: field groups table, per-component Configure sections, Inputs/Outputs as UI-matching tables, Test the Module section, bundle download link. | | 2026-09-30 | Initial publication. | The UI (user interface) is a device's end-user interaction and communication point. It can include display screens, keyboards, and mouse. It is also how a user interacts with your application. Also known as Unqork Users, or Designer Users; is anyone who is inside the Unqork platform. A URL (uniform resource locator) is a unique identifier used to locate a resource on the internet. Also known as a web address. Also known as Unqork Users, or Designer Users; is anyone who is inside the Unqork platform. Includes the Short Answer component, Long Answer component, Select Boxes, Radio component, Dropdown, Number component and Single Checkbox. A key-value pair is a fundamental data structure where a unique "key" is associated with a specific "value," used for organizing and retrieving data efficiently, like in dictionaries or databases. An API endpoint is the location where an API receives requests for a specific resource on its server. It's the point of contact between an API client and an API server, and is usually a uniform resource locator (URL) that provides the location of the resource. A Property ID is the unique field ID used by Unqork to track and link components in your module. Rendering is the process of loading components and displaying the final result on the front-end screen. A Property ID is the unique field ID used by Unqork to track and link components in your module. Deteremines how the component triggers. The component fires when the page or called module loads without an existing submission ID. Dashboards and remote execute modules are great uses for this trigger. Label Text conveys what the input component is and what information it displays. Enter the purpose of the corresponding component or field. Enter inputs components and actions you want the component to perform.. Enter outputs components and actions you want the component to perform. Enter the Property ID of the component that you want to trigger on each button-click. The HTTP POST method is used to send data to a server to create or update a resource, typically including the data in the body of the request. The Post Trigger value fires after a component has completed its action. For example, post triggering a component to display the data received from a Plug-In component's API call. Base64 is an encoding and decoding technique used to convert binary data to an ASCII (American Standard for Information Interchange) text format. A string is an object that represents a sequence of characters. Strings typically hold data represented in text form. A definition An API endpoint is the location where an API receives requests for a specific resource on its server. It's the point of contact between an API client and an API server, and is usually a uniform resource locator (URL) that provides the location of the resource. A naming convention for computer programming. Use camelCase for Property IDs, for example: newUser, lastName, & rdoButton. A key-value pair is a fundamental data structure where a unique "key" is associated with a specific "value," used for organizing and retrieving data efficiently, like in dictionaries or databases. Express View is how your end-user views your application. Express View also lets you preview your applications to test your configuration and view the styling. This is also the view your end-users will see when interacting with your application. After configuring a module, click Preview in the Module Builder to interact with the module in Express View. ## Related - [Build a Bulk Download Module](/build-a-bulk-download-module.md) - [Bulk Operations: Utilities](/bulk-operations-utilities.md) - [Record Operations API](/record-operations-api.md)