Importer SDK
@expresscsv/sdk is centered around the CSVImporter class. You configure it once with new CSVImporter(options), then call open() when you want to start an import.
new CSVImporter(options)
Constructor options
| Option | Description | Type | Required | Default |
|---|---|---|---|---|
schema | Schema definition created with x.row() | Schema | Yes | — |
getSessionToken | Async callback that asks your backend for a short-lived import session token | () => Promise<string> | Yes | — |
importNamespace | Stable namespace string your app assigns to this importer configuration. Keep it the same for the same workflow; use a different value for different importers. | string | Yes | — |
title | Title shown in the importer header | string | No | — |
preload | Preload the importer in a hidden iframe for instant display | boolean | No | true |
debug | Enable debug logging | boolean | No | false |
theme | Theme variable overrides (see Styling) | Theme | No | — |
colorMode | 'light', 'dark', or 'system' | ColorModePref | No | — |
customCSS | Custom CSS injected into the importer | string | No | — |
fonts | Custom font sources | Record<string, FontSource> | No | — |
stepDisplay | Step indicator style | 'progressBar', 'segmented', or 'numbered' | No | 'progressBar' |
previewSchemaBeforeUpload | Show expected columns before upload | boolean | No | true |
columnMatching | Configure managed column matching or provide a custom matcher | { type: "managed"; exact?: boolean; caseInsensitive?: boolean; normalized?: boolean; inference?: boolean } | { type: "custom"; columnMatchHandler: (...) => Promise<...> } | No | undefined |
promptedEdits | Enable managed prompted edits or provide a custom edit handler | { type: "managed" } | { type: "custom"; promptedEditHandler: (...) => Promise<...> } | No | undefined |
templateDownload | Offer downloadable template files | TemplateDownloadOptions<TSchema> | No | — |
sessionRecovery | Enable recovered sessions with either local recovery or a custom adapter implementing get, set, and remove | SessionRecoveryOptions | No | — |
locale | Locale string overrides (see Localization) | DeepPartial<ExpressCSVLocaleInput> | No | — |
disableStatusStep | Skip the success/error status screen | boolean | No | — |
Instance surface
| Member | Description |
|---|---|
open(options) | Starts an import. Requires onData on options. |
close(reason?) | Closes the importer (preload mode hides the iframe for reuse; normal mode tears down). |
restart(newOptions?) | Resets and reopens when getCanRestart() is true (typically after preload close). |
getStatus() | Current ImporterStatus from the SDK. |
getMode() | ImporterMode.PRELOAD or ImporterMode.NORMAL. |
getIsReady() | true when status is READY or OPEN. |
getIsOpen() | true while the importer is open. |
getCanRestart() | true when the instance can run restart(). |
getLastError() | Most recent error, if any. |
getConnectionStatus() | Whether the iframe RPC connection is up. |
getStatusSnapshot() | Snapshot of status helpers (same fields the getters expose). |
subscribeToStatusChanges(listener) | Subscribe to ImporterStatus changes; returns an unsubscribe function. |
While the iframe is loading or an import session is starting, getStatus() is INITIALIZING or OPENING. Use getStatus() or subscribeToStatusChanges() instead of a single initialization flag.
open(options)
Options passed to open().
| Option | Description | Type | Required |
|---|---|---|---|
onData | Callback for each chunk. Call next() after your backend accepts the current chunk. | (chunk: RecordsChunk<T>, next: () => void) => void or Promise<void> | Yes |
chunkSize | Delivery packet size. Defaults to { unit: "kb", value: 500 }. kb uses decimal kilobytes (1 KB = 1000 bytes). Use { unit: "kb", value: 500 } for KB or { unit: "rows", value: 500 } for row counts. Zero or negative values send all records in one chunk. | ChunkSize | No |
onComplete | Called when all chunks have been processed | (context: { sessionId: string; deliveryId: string }) => void | No |
onCancel | Called when the user cancels the import | (context: { sessionId: string }) => void | No |
onError | Called when an error occurs. deliveryId is present for delivery failures. | (error: Error, context: { sessionId: string; deliveryId?: string }) => void | No |
onOpen | Called when the importer opens | (context: { sessionId: string }) => void | No |
onStepChange | Called when the importer step changes | (stepId: ImporterStep, previousStepId?: ImporterStep) => void | No |
RecordsChunk<T>
| Property | Description | Type |
|---|---|---|
records | Validated records for this chunk, typed from your schema | T[] |
totalChunks | Total number of chunks in the delivery | number |
chunkIndex | 0-based index of the current chunk within this delivery | number |
totalRecords | Total records across all chunks | number |
sessionId | Stable ID for this import run. Use it to group chunks and lifecycle callbacks. | string |
deliveryId | Stable ID for the delivery created when the user finishes the import. Use it with sessionId and chunkIndex when saving each chunk to your import chunk staging table (a database table or store). | string |
ImporterStatus
The importer moves through these statuses during its lifecycle:
| Status | Description |
|---|---|
UNINITIALIZED | Initial status before the importer iframe is created |
INITIALIZING | Iframe is loading and establishing a connection |
READY | Importer is loaded, preloaded, and ready to be opened |
OPENING | open() has been called; creating an import session |
OPEN | Importer is visible and the user is interacting with it |
CLOSING | Importer is in the process of closing |
RESETTING | Importer is resetting for a new import |
ERROR | An error occurred (check getLastError()) |
DESTROYED | Importer has been torn down (normal mode after close) |
Typical flow: UNINITIALIZED → INITIALIZING → READY → OPENING → OPEN → CLOSING → READY
ImporterStep
The importer step IDs passed to onStepChange:
| Step ID | Description |
|---|---|
'upload' | File upload and optional schema preview |
'select-sheet' | Sheet selection (multi-sheet files only) |
'select-header' | Header row selection |
'match-columns' | Map CSV columns to schema fields |
'match-options' | Map option values for select/multiselect fields |
'review' | Review, edit, and validate data before import |
Preloading
preload: true(default): the importer iframe loads in the background soopen()displays instantly with no loading screenpreload: false: the iframe is created only whenopen()is called; the user sees a brief loading indicator- Use
preload: falsewhen the importer is rarely used and you want to avoid the upfront iframe cost
Exported Types
All of these are importable from @expresscsv/sdk:
| Type | Description |
|---|---|
Infer<TSchema> | Extracts the row type from a schema |
SDKOptions | Options for new CSVImporter() |
InferCSVImporter | Helper to infer CSVImporter type from a schema |
OpenOptions | Options for open() |
ImportSessionContext | { sessionId: string } passed to session-scoped lifecycle callbacks |
ImportDeliveryContext | { sessionId: string; deliveryId: string } passed to delivery-scoped lifecycle callbacks |
ImportErrorContext | { sessionId: string; deliveryId?: string } passed to onError |
RecordsChunk | Chunk delivered to onData |
SessionRecoveryOptions | Configuration for recovered sessions |
LocalSessionRecoveryOptions | Built-in browser recovery configuration |
CustomSessionRecoveryOptions | Custom recovery adapter configuration |
SessionRecoveryKey | Opaque key generated for a recovered session lookup |
RecoveredSession | Wrapper type for a recovered session payload in the importer |
RecoveredSessionData | Row data and column keys for a recovered session |
SchemaFieldName | Union of string keys inferred from a schema |
ManagedColumnMatchingOptions | { type: "managed"; ... } |
CustomColumnMatchingOptions | { type: "custom"; columnMatchHandler } |
ColumnMatchingOptions | Managed or custom column matching |
ColumnMatchHandler | Custom column matching handler alias |
ColumnMatchHandlerResult | Result type for custom column matching |
ManagedPromptedEditsOptions | { type: "managed" } |
CustomPromptedEditsOptions | { type: "custom"; promptedEditHandler } |
PromptedEditsOptions | Managed or custom prompted edits |
PromptedEditHandler | Custom prompted edits handler alias |
PromptedEditResult | Result type for custom prompted edits |
ColumnMatchingFn | Low-level custom column matching handler type |
ColumnMatchingParams | Input passed to a custom column matching handler |
ColumnMatchingResult | Result returned by a custom column matching handler |
ColumnMatchingSourceColumn | Source column payload for matching |
ColumnMatchingTargetField | Target field payload for matching |
ColumnMatch | A single source-to-field match |
PromptedEditsFn | Low-level custom prompted edits handler type |
PromptedEditsParams | Input passed to a custom prompted edits handler |
PromptedEditsResult | Result returned by a custom prompted edits handler |
PromptedEditsField | Field metadata for prompted edits |
PromptedEditsRow | Row payload for prompted edits |
PromptedEditsChange | A single add/update/remove change |
Theme | Theme variable overrides (single or dual-mode) |
ColorModePref | 'light', 'dark', or 'system' |
FontSource | Font source (Google or custom URL) |
TailwindThemeVars | Theme variable names |
ImporterStatus | Importer lifecycle status enum |
ImporterMode | Importer preload mode enum |
ImporterStep | Importer step IDs |
TemplateDownloadConfig | Template download configuration |
TemplateDownloadOptions | Template options with schema-typed example rows |
TemplateDownloadFormat | 'csv' or 'xlsx' |
TemplateDownloadExampleRow | Example row type for templates |
ExpressCSVLocaleInput | Full locale type |
DeepPartial | Deep partial utility type |
ImportCancelledError | Error thrown when import is cancelled |
ExType | Schema type helper from @expresscsv/fields |
ExBaseDef | Base definition type from @expresscsv/fields |
x | Schema builder (value, not a type) |