How to rename csv column headers to match database field names
- Step 1List the target field names from your schema — Read them straight from the
CREATE TABLEstatement or your migration tool's mapping. Note the exact spelling and case. In PostgreSQL, unquoted identifiers fold to lowercase, socustomer_nameandCustomer_Nameare the same unless you quote them; in MySQL, column-name case sensitivity depends on the platform but values matched in a loader must spell the field correctly. - Step 2Export the source data as CSV — Export from the spreadsheet, the legacy system, or the previous database as
.csv(the tool also reads.tsvand.txt; PapaParse auto-detects the delimiter). Ensure the first row is the header row — that's what the rename list is built from. - Step 3Drop the CSV onto the tool above — PapaParse parses it in your browser and lists every column with a rename box. The displayed header is trimmed of surrounding whitespace, but the rename writes exactly what you type — type the field name with the exact case your engine requires.
- Step 4Type the database field name next to each column —
Customer Name→customer_name,E-mail→email,DOB→date_of_birth. Leave a box blank to keep a header that already matches. For aCOPY ... WITH (HEADER)load, the CSV header names should be the table's column names. - Step 5Run and download the schema-aligned CSV — The button reads
Rename N headers. The result shows Headers renamed, Data rows, and a 10-row preview. Click Download for<name>.renamed.csv— a comma-delimited CSV (no BOM), whichLOAD DATAand\copyread directly. - Step 6Run the import and verify column alignment — Feed the renamed CSV into
LOAD DATA INFILE,\copy, or your migration tool. Use a header-aware load (IGNORE 1 LINESfor MySQL with a matching column list, orWITH (HEADER)for Postgres). Verify a few rows landed in the right columns before loading the whole table.
Source header to schema field — mapping examples
Spreadsheet/legacy headers and the database field name to rename them to. Confirm the exact case against your CREATE TABLE.
| Source header | Schema field | Convention |
|---|---|---|
Customer Name | customer_name | snake_case, lowercase (Postgres-safe unquoted) |
E-mail, Email Address | email | Strip punctuation, single token |
DOB | date_of_birth | Expand abbreviations the schema spells out |
Order # | order_id | Replace symbols a column name can't contain |
Created | created_at | Match the schema's timestamp convention |
Status | "status" / status | status is fine in most engines; quote if your tool treats it as reserved |
UserID | user_id | Split camelCase into snake_case if the schema uses it |
Rename vs. the rest of a migration
The rename aligns column names. Type coercion, NULL handling, and column trimming belong to the loader or a separate step.
| Concern | Header rename? | Where it actually happens |
|---|---|---|
| Column name must match the field | Yes | This tool |
'NULL' / empty string → real NULL | No | Loader option (e.g. NULL '' in Postgres COPY) |
| Date string → DATE type | No | Database type cast on insert / staging table |
| Drop columns not in the schema | Leave blank, or | csv-column-remover |
| Reorder to match a positional column list | No | csv-column-reorder, or use a named column list in the loader |
| Trim stray whitespace in values | No | csv-whitespace-trimmer |
Cookbook
Source header rows and their schema-aligned output. Data rows shown to confirm values are preserved for the database to cast.
Spreadsheet to snake_case schema
ExampleA spreadsheet of customers with display-style headers. The Postgres table uses lowercase snake_case. Three renames align it; the data is left for the database to type-cast.
Input header: Customer Name,Email Address,Sign Up Date Acme Ltd,ops@acme.example,2025-11-03 Renames typed: Customer Name -> customer_name Email Address -> email Sign Up Date -> created_at Output header: customer_name,email,created_at Acme Ltd,ops@acme.example,2025-11-03
Headers with symbols a column name can't contain
ExampleLegacy exports often use # and spaces. SQL identifiers can't (or shouldn't) contain those. Rename them to clean field names before the load.
Input header: Order #,Item Qty,Unit Price (GBP) 1001,3,19.99 Renames typed: Order # -> order_id Item Qty -> quantity Unit Price (GBP) -> unit_price Output header: order_id,quantity,unit_price 1001,3,19.99
Match exact case for a case-sensitive engine
ExampleWhen the target uses quoted, case-sensitive identifiers, type the exact case. The tool writes whatever you enter, so customerId stays mixed-case.
Input header: Name,Customer Id Acme,42 Renames typed: Name -> name Customer Id -> customerId (quoted identifier in the schema) Output header: name,customerId Acme,42 → In Postgres, the table must define "customerId" (quoted) to match.
Leave already-correct headers blank
ExampleIf the export mostly matches the schema, only relabel the columns that differ. The renamed-count confirms the scope of the change.
Input header: id,Full Name,email,created Renames typed (id and email left blank): Full Name -> full_name created -> created_at Output header: id,full_name,email,created_at → Headers renamed: 2
Two legacy columns named the same
ExampleA wide legacy export repeats a generic header. Rename by position so each maps to its own schema field.
Input header: id,addr,addr 7,12 High St,London Renames typed (by position): column 2 addr -> address_line1 column 3 addr -> city Output header: id,address_line1,city 7,12 High St,London
Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Case mismatch on a case-sensitive engine
Load fails — column not foundPostgreSQL folds unquoted identifiers to lowercase, so Customer_Name in your CSV header maps to customer_name — but if the table was created with a quoted "Customer_Name", the names won't match. Type the exact case the schema uses. The tool writes whatever you enter verbatim, so you control case precisely; verify against the CREATE TABLE.
Field name is a reserved SQL word
Loader may rejectRenaming a header to order, user, select, or from produces a valid CSV, but the loader or migration tool may choke on the reserved word unless it quotes identifiers. The tool will write exactly what you type — including the reserved word. How it's handled is down to your loader's quoting; consider a non-reserved name (order_record) or ensure your tool quotes identifiers.
Renamed but values aren't cast (dates, NULLs)
Type/NULL handling separateThe rename aligns the column name; it does not turn '' into a real NULL or a string into a DATE. That's the loader's job: NULL '' in a Postgres COPY, or a staging table with explicit casts. The rename passes data cells through unchanged so the database does the typing — don't expect the rename to coerce values.
Two headers renamed to the same field
Duplicate columnsThe tool renames by position and won't stop you producing two columns named email. A loader with a named column list will reject the ambiguity or load unpredictably. Map each source column to a distinct field, and drop any genuinely redundant column with csv-column-remover before the load.
More CSV columns than table fields
Extra columnsRenaming doesn't remove columns. If the CSV has columns the table doesn't, a \copy or LOAD DATA with an exact column list will error on the count mismatch. Either drop the extras with csv-column-remover, or use a named column list in the loader that references only the fields you want.
Column order must match a positional loader
Order unchangedHeader rename doesn't reorder columns. A loader that maps by position (not by header name) needs the columns in schema order. Use csv-column-reorder to set the order, or prefer a name-aware load (WITH (HEADER) / explicit column list) so order doesn't matter.
Source is tab- or semicolon-delimited
SupportedPapaParse auto-detects the delimiter on input, so a .tsv export or a semicolon-separated legacy file lists its columns correctly. The download is comma-delimited CSV. If your loader expects a specific delimiter, set it in the loader's options (FIELDS TERMINATED BY ',') to match the output.
Full table extract exceeds the free limit
Pro overlayA production table can easily pass 500 rows or 2 MB, triggering the Pro overlay (the row check runs on the result). Pro raises the limits to 100 MB / 100,000 rows. For a one-off migration you can rename a small sample to validate the mapping, then upgrade to process the full extract.
Frequently asked questions
Does this handle case sensitivity?
Yes — you type the exact case you need, and the tool writes it verbatim. Use lowercase for unquoted PostgreSQL identifiers (which fold to lowercase anyway), UPPER_CASE if your schema uses it, or camelCase for quoted, case-sensitive identifiers. Always match the case in your CREATE TABLE; the rename gives you full control but won't second-guess your schema.
What if my target schema uses a reserved SQL word as a column name?
The tool will rename the header to whatever you type, including a reserved word like order or user. Whether the load succeeds depends on your loader quoting identifiers. If it doesn't quote, pick a non-reserved field name (for example order_record), or configure your migration tool to quote identifiers so the reserved word is accepted.
Can I rename headers and remove columns in the same step?
Not in one step. Rename the headers here first, then run the file through csv-column-remover to drop any columns not in the schema. Keeping the two operations separate means you can verify the mapping before deciding which columns to discard.
Will the rename cast my dates or convert empty strings to NULL?
No. The rename only changes the header row; data cells pass through unchanged. Type casting (string → DATE) and NULL handling ('' → NULL) are the loader's responsibility — set NULL '' in a Postgres COPY, or use a staging table with explicit casts. The rename makes column names match; the database does the typing.
Does it work for MySQL, PostgreSQL, and SQLite?
Yes — header rename is engine-agnostic because it just sets the column names in the CSV. It suits MySQL LOAD DATA INFILE, PostgreSQL \copy ... WITH (HEADER), SQLite's .import, and ORM/migration-framework imports. Match the field names and case your specific engine and loader expect.
My loader maps by column position, not name — does renaming help?
Only partly. If the loader ignores headers and maps by position, the column order matters more than the names. Renaming keeps the header readable, but you'll also need to reorder columns to match the schema with csv-column-reorder. Prefer a name-aware load (WITH (HEADER) or an explicit column list) so order is irrelevant.
What if the CSV has more columns than the table?
Renaming doesn't remove columns, so an exact-count load will fail on the mismatch. Drop the surplus columns with csv-column-remover after renaming, or use a named column list in your loader that references only the fields present in the table.
Are the data values altered before the database sees them?
No. The tool rewrites only the header row; every value below is passed through byte-for-byte, leaving the database to cast it according to the column type. The result panel shows a Data rows count so you can confirm no rows were added or lost during the rename.
Does the output add a BOM, and will that affect the load?
No BOM is added — the download is plain UTF-8 written by Papa.unparse. That's ideal for LOAD DATA and \copy, which can choke on an unexpected BOM at the start of the first header. So the absence of a BOM here actually helps clean SQL loads.
Is there a row or file-size limit for a migration extract?
Free handles up to 2 MB and 500 data rows per job; beyond that you'll see the Pro overlay (the row check runs on the renamed result). Pro raises the limits to 100 MB and 100,000 rows, which covers most single-table extracts. For a quick test, rename a small sample to validate the mapping first.
Is production data uploaded anywhere?
No. PapaParse runs entirely in your browser; rows that may contain PII or financial data never reach a JAD server. Only a usage counter (no content) is recorded when signed in, and you can opt out in account settings. The rename keeps the migration data on your machine, which matters for compliance during a database move.
Can I automate header rename in a migration pipeline?
Yes. GET /api/v1/tools/csv-header-rename returns the option schema (a renames map keyed by column index). Pair the @jadapps/runner once and POST your extract to 127.0.0.1:9789/v1/tools/csv-header-rename/run. The runner executes locally, so the data stays on your machine — fit it into an extract → rename → load script.
How do I also trim whitespace from values before loading?
The rename doesn't touch cell values, so leading/trailing spaces stay. Run the file through csv-whitespace-trimmer before or after renaming to clean the data, or csv-cleaner for a broader pass. Then load the cleaned, schema-aligned CSV.
Privacy first
Processing runs locally in your browser with PapaParse. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.