Importing customers from CSV
Use this to bring an existing customer list over from another system, or to update notes and credit limits on hundreds of customers at once. It's upsert by email — if the email already exists in your customer list, the row updates it; if not, a new customer is created.
Open it from Customers → Import CSV, or go to
/dashboard/customers/import.
The three-step flow
- Upload your CSV. Max 2 MB, max 5,000 rows per import.
- Preview — Distribu parses the file, shows how many rows would be created, updated, or left unchanged, and surfaces any validation issues.
- Apply — click Import to run it. The whole batch runs in a single database transaction: either everything succeeds or nothing is written.
Re-uploading or tweaking the mapping between steps is safe — nothing is written until you hit Import on the preview.
Columns
The importer recognizes five columns:
| Column | Required? | Notes |
|---|---|---|
email | Yes | Used to match rows. Duplicates in a single file are rejected. |
name | No | Up to 100 chars. Empty → null. |
status | No | ACTIVE or BLOCKED. Defaults to ACTIVE. |
notes | No | Up to 2000 chars. Empty → null. |
creditLimit | No | Non-negative number, up to 2 decimal places. Empty → null (no limit). |
Only email is required. A minimal valid CSV is literally:
email
acme@example.com
blueplate@example.com
…which creates two customers with no name, ACTIVE status, no notes, and
no credit limit.
See Customers CSV format for the full column reference and a downloadable template.
Passwords are never set by import
CSV import does not set passwords. Customers you import this way will appear in your dashboard immediately, but they can't log in to your storefront until they set a password themselves. Two things to know:
- The
passwordcolumn doesn't exist — even if you include it, it's ignored. - Imported customers go through the password-reset flow at
/store/{your-slug}/loginto set one.
This is deliberate — we never accept plaintext passwords over CSV, and generating random ones you'd have to hand-type to customers isn't useful.
Column auto-detection
Distribu auto-maps common header variations to the canonical name. For
example, email, e-mail, email_address, and contact_email all map to
email.
- email —
email,emailaddress,e-mail,contactemail,contact_email - name —
name,full_name,customer_name,contact_name,company_name - status —
status,state - notes —
notes,note,comments,comment,remarks - creditLimit —
creditlimit,credit_limit,credit,limit,creditline,credit_line
If a header doesn't auto-detect, the preview shows dropdowns so you can pick the source column by hand. Once you confirm, the preview re-runs with the override.
Status parsing
The status column is forgiving about values. Anything not in the "blocked"
list below is treated as ACTIVE:
| Value | Interpreted as |
|---|---|
blocked, suspended, inactive, disabled, false, 0 | BLOCKED |
| empty | ACTIVE |
anything else (active, ok, 1, true…) | ACTIVE |
Case-insensitive, and leading/trailing whitespace is trimmed.
How upsert works
For each row, Distribu looks up existing customers in your company by email:
- Not found — create a new customer with the row's fields. Counts against your plan's customer limit.
- Found and every field matches — skip. Counts as "unchanged".
- Found but something differs — update the existing customer. Fields
compared:
name,status,notes,creditLimit. Other fields (orders, addresses, contacts, passwords) are never touched.
Existing customers that aren't in the CSV are left alone. Importing a 100-row file doesn't block or delete the other 900 customers in your list.
Emails are normalized. The importer lowercases every email before matching, so
Acme@Example.comandacme@example.comare the same row.
Preview view
Once you upload, you'll see:
- A summary: N to create / M to update / K unchanged.
- Up to 50 sample rows showing the action Distribu would take.
- A list of any issues — row number + error message for anything that failed validation (invalid email, negative credit limit, duplicate email in file, etc.).
- A warning if the import would exceed your plan's customer limit.
If there are issues, the Import button is disabled. Fix the CSV and re-upload.
Limits
| Max file size | 2 MB |
| Max rows per import | 5,000 |
Plan maxCustomers | Enforced on create rows only. Updates never count against the limit. |
For customer lists larger than 5,000, split the file and import in batches.
Exporting
From Customers, click Export CSV to download your full customer list in the same 5-column format. Round-trip safe — export, edit in Excel, and re-import.
The endpoint is also available directly at
/dashboard/customers/export.
Audit trail
Every successful import writes a single audit-log entry with action
CustomerBulkImported, metadata { created: N, updated: M }, and the user
who ran it. Visible in
Settings → Audit log.
Next: Customer contacts.
