Appearance
CSV Import
Import CSV files into any view with a visual field mapping dialog. Map CSV columns to view fields, preview records before importing, and save mapping configurations for repeated use.
Opening the Import Dialog
There are two ways to start an import:
- Toolbar — click the Import button in the top toolbar
- File menu — click File > Import Data
The Import button is only enabled when the current view allows adding rows.
Upload
Select a .csv, .tsv, or .txt file. The dialog scans the file to detect columns and count rows without loading the entire file into memory — files up to 100 MB are supported.
Field Mapping
After selecting a file, the mapping table shows:
| Column | Description |
|---|---|
| CSV Fields | Values from the current record, numbered by CSV column position |
| Table Target Fields | View column name with data type badge (e.g. VARCHAR(255)) and constraint badges (PRIMARY, UNIQUE) |
Auto-Mapping
Columns are automatically matched by name:
- CSV header matches view column display name (case-insensitive)
- Fallback: matches field name (camelCase API name)
- Fallback: matches database column name (snake_case)
Unmapped columns show Default: <null> and are skipped during import.
Manual Mapping
Click any CSV cell to open a dropdown and reassign the CSV column for that row. Select — to unmap.
Record Browser
Use the < > paginator at the bottom to browse through records and verify that CSV values land in the correct columns.
Options
| Option | Description |
|---|---|
| First line contains field names | When checked, the first CSV row is used as column headers for auto-mapping. When unchecked, columns are mapped by position. |
| Import Method | INSERT creates new rows. UPDATE updates existing rows (requires primary key mapped). |
| Align field names by | Controls CSV column ordering: File order (original position) or Alphabetical (sorted by header name). |
Column Handling
| Column Type | Importable? | Notes |
|---|---|---|
| Regular columns | Yes | User provides values |
| UUID primary key | Yes | Map from CSV or leave blank for auto-generation |
| Auto-increment primary key | No | Database generates automatically |
| FK columns (with edit mode) | Yes | Provide the foreign key value |
| Relationship display columns | No | Read-only joined data |
| Computed / formula columns | No | Calculated at query time |
| Auto-set timestamps | No | Created/updated timestamps are generated automatically |
| Display groups | Expanded | Individual member columns shown separately |
Saved Mappings
Save a mapping configuration by entering a name and clicking Save above the mapping table. Saved mappings can be loaded from the dropdown when importing the same CSV structure again.
Mappings are saved per view. Visibility can be Private (only you) or Shared (all view members).
Import Execution
Click Import to start. Rows are sent in batches of 500 to the server. A progress bar shows batch progress, success count, and error count.
Validation on import
Imported rows go through the same validation as a value typed into a cell: column constraints (required, max length, email, and the rest) and cross-field entity constraints. A row that fails is reported with its row number and reason, and skipped — the rest of the file still imports. Click Export Errors CSV to download every rejection with its details.
This means an import can partially succeed, which is deliberate: one bad row in a 5,000-row file shouldn't cost you the other 4,999.
TIP
Fix the rejected rows in the exported errors CSV and import that file again — it has the same columns, so your saved mapping still applies.
WARNING
Errors the database alone can detect — a unique value that collides with a row already in the table, a foreign key pointing at something that isn't there — are found when the batch is written, not during validation. Those fail the batch of 500 they belong to, and the report says so rather than blaming a single row. Validation catches the common cases first, so this is the exception.
API Endpoint
The bulk insert endpoint can also be called directly:
POST /api/data/bulk/{viewUuid}/insertRequest body:
json
{
"rows": [
{ "name": "Angola", "code": "AO" },
{ "name": "Argentina", "code": "AR" }
]
}Response (201):
json
{
"viewUuid": "abc-123",
"totalCount": 2,
"successCount": 2,
"failureCount": 0,
"skippedCount": 0,
"errors": []
}Maximum 1000 rows per request. Field names use the camelCase API field names (same as the single-row insert endpoint).
Re-importing without duplicating
By default an import only ever adds rows, so running the same file twice gives you everything twice. Name the columns that identify a row and the same file becomes a correction instead:
json
{
"rows": [{ "email": "[email protected]", "name": "Ada L." }],
"conflictColumns": ["email"],
"onConflict": "UPDATE"
}onConflict | What happens to a row that already exists |
|---|---|
ERROR | The default. The database refuses the batch, and nothing is imported. |
IGNORE | The stored row is kept and the incoming one is skipped. Skipped rows are counted in skippedCount, not failureCount — they are the requested outcome, not a failure. |
UPDATE | The stored row's other columns are overwritten with the incoming values. The match columns themselves are never rewritten. |
The match columns need a unique index
A database can only recognise a duplicate if a unique index or primary key says those columns identify a row. Without one, PostgreSQL refuses the statement and the import returns an error saying so — nothing is written. Add the index first, or import without a match column.
MySQL matches on any unique key
PostgreSQL matches on exactly the columns you name. MySQL has no equivalent, so it reconciles on any unique key on the table — a row colliding on a different unique column is updated too. Worth knowing if your table has more than one.