This article explains how the Import Data feature works in Administrate, including how CSV templates are structured, how data is processed, and how fields and lookups behave during import.
Contents
- Overview
- How imports work
- Import processing and statuses
- Understanding CSV templates
- Field types and formats
- Lookup behavior
- Common entity behavior
- How updates treat blank cells
- Fields that do not appear on templates
- Handling failures and partial imports
- Permissions
Overview
The Import Data feature allows you to create and update records in bulk using CSV files. It supports Accounts, Contacts, Events, Course Templates, Resources, and other entities across the platform.
Imports use the same structure as the GraphQL API, meaning:
- available fields reflect the current system configuration
- custom fields are supported automatically
- new functionality becomes available without template changes
How imports work
Each import follows a consistent process:
- select an entity (for example, Event or Contact)
- select an action (for example, create or update)
- provide your data: download the generated template, use a report export, or upload your own file
- populate the template with your data
- upload the file and run the import
The action you choose decides what the import does: create makes new records, update changes existing ones, and upsert (available for entities with external IDs) creates or updates depending on whether the external ID already matches a record. See Choosing Create, Update, or Upsert.
Import processing and statuses
Imports are processed asynchronously in scheduled batches.
You may see the following statuses:
- Pending: queued for processing
- In Progress: currently being processed
- Completed: all rows processed successfully
- Partial: some rows succeeded, others failed
- Failed: no rows processed successfully
Large imports are processed in batches. For example, files with 10,000+ rows may be split into multiple processing cycles.
Understanding CSV templates
Every import template includes four required header rows. These rows define how the system maps your data and must not be modified or removed.
| Row 1 | Field name | Example: Email Address |
| Row 2 | GraphQL field reference | Example: input/emailAddress |
| Row 3 | Field description | Describes expected data |
| Row 4 | Field type and requirements | Example: Text (Optional) |
| Row 5+ | Your data | Begin entering values here |
You must:
- start entering data from row 5
- keep the file in CSV format
- follow formatting rules shown in the template
Field types and formats
| Field type | Behavior |
|---|---|
| ID | Requires a Base64-encoded ID value |
| Text | Accepts free text |
| Text (Optional) | May be left blank |
| Fixed | Must match one of the allowed values |
| Lookup | Finds existing records by name or ID |
| LocalDateTime | ISO 8601 format (e.g. 2025-11-04T14:00:00) |
| TimeZoned DateTime | Includes timezone offset (e.g. 2025-11-04T14:00:00+03:00) |
| TimeZone Name | Uses standard TZ identifiers (e.g. America/New_York) |
Lookup behavior
Lookup fields connect records across entities.
When using a lookup:
- the system first attempts to match by the entity's natural identifier, such as a name or, for courses, the course code
- if no match is found, it attempts to match by encoded ID
- if no match is found, the row fails
Lookup format:
lookup(entity, field)
Examples:
- lookup(contacts, name)
- lookup(locations, name)
- lookup(currencies, code)
Common entity behavior
Some entities require specific formats or field combinations:
- Events: require correct date/time formatting and timezone handling
- Locations and Tax Types: use lookup fields to match existing records
- Optional fields: may be left blank, but some fields require paired values (for example, ID vs Name)
Different actions (such as create, update, addStaff, or addPrices) may require different fields.
How updates treat blank cells
When you run an update import, a blank cell means "leave this field alone", not "clear this field":
- Blank cells never change existing data. A blank cell is omitted from the update entirely, so the current value is left untouched. This applies to every field type: text fields, dates, lookups, and list-style fields. The one exception is deliberate: if you configure value matching during field mapping to give empty cells a default value, those cells import that default instead of being skipped.
- You can safely send sparse update files. Include only the columns you want to change plus the identifying column; everything you leave blank keeps its current value.
- Blank cells cannot clear a field. There is no value you can put in an import file to blank out existing data. To clear a field, edit the record in Administrate or use the GraphQL API, which supports setting a field to null explicitly.
- List-style fields are replaced, not merged. When you do provide a value for a list-style field (for example, workplaces), the imported list replaces the existing one in full. Include every entry the record should keep.
- Email addresses and phone numbers replace by usage. Providing an email of one usage updates that usage only; addresses of other usages on the record are retained.
Fields that do not appear on templates
If a field you see on an Administrate screen seems to be missing from an import template, check two things before treating it as a gap:
- Template columns are named after the underlying API fields, which can differ from screen labels. For example, the field labelled Language on the contact form appears on contact templates as Preferred Locale (with a separate Locale column for the LMS content language). Search the template for likely synonyms before concluding a field is missing.
- Custom System Fields are not included on contact templates. These are the older, fixed built-in contact fields, renamed per instance and managed by Administrate, so they appear under whatever label your organization gave them (for example, an instructor text field relabelled to a specialism, or a legacy date field relabelled to a contract date). They do not appear in Control Panel → Custom Fields; see Custom Fields for the difference. They are different from Custom Fields, which do get their own template columns and can be updated in bulk. Custom System Field values are set on the record in Administrate or through the GraphQL API; if you need bulk updates for one, consider moving the data to a Custom Field.
Long text limits: free-text fields such as the contact Notes field hold up to 65,535 bytes, roughly 64,000 characters of plain Latin text and fewer when accented or non-Latin characters are used. No shorter limit is enforced.
Handling failures and partial imports
When an import fails or completes partially:
- download the failure file from the import record
- review the error message for each failed row
- correct only the failed rows
- re-import the corrected subset
Common error causes include:
- invalid or missing IDs
- incorrect field formats
- lookup values that do not match existing records
Permissions
Users must have the Import Data - Edit permission to access the import feature.
Users can only create or update records for entities they have permission to access.