Drop in a CSV and get a data type for every column, a primary key suggestion, and ready-to-copy CREATE TABLE SQL, a TypeScript interface, or JSON Schema.
This tool runs entirely in your browser. What you enter is never sent anywhere.Your input is never sent anywhere.
DetailsEverything runs in your browser. Your CSV is never sent to a server.
Drag and drop a CSV file here
or choose one from your computer
Turn a CSV into a draft table definition
Loading a CSV into a database starts with deciding what type each column should be. This tool reads every row of your file, picks a type for each column, and writes the table definition for you.
Columns are classified as integer, decimal, boolean, date, datetime, email, URL, enum, or text. A confidence percentage shows how many non-empty values matched the chosen pattern, so columns with mixed or messy data stand out. You can override any type from a dropdown, and the output updates right away.
The result comes out as CREATE TABLE for MySQL, PostgreSQL, and SQLite, a TypeScript interface, or a JSON Schema. Everything is computed in your browser, and the file is never uploaded.
Typical uses: import prep, prototypes, API types
Importing a file from a vendor or client
A partner sends a CSV export and you need a table to hold it. Get a first-draft CREATE TABLE instead of checking every column by hand.
Prototyping a schema from sample data
Start with a few hundred sample rows, generate the DDL, and use it as the starting point for your real schema.
Typing an API response or frontend model
Generate a TypeScript interface or a JSON Schema from the same CSV, so your frontend types and database columns start out in agreement.
Spotting messy columns before you load
Columns with empty cells are flagged as nullable, and a confidence below 100% means some values do not fit the detected type. Use that to decide which columns need cleanup first.
How to generate a CREATE TABLE statement from a CSV
- Drag a CSV or TSV file onto the upload area, or switch to Paste text, paste your data, and click Analyze CSV. Load sample CSV shows an example.
- Check the delimiter (auto-detect by default) and whether the first row is a header. Turn on snake_case if you want clean column names.
- Review each column's detected type, confidence, nullable flag, and sample values. Use the Change type dropdown to fix any wrong guess.
- Set a table name, pick MySQL, PostgreSQL, SQLite, TypeScript, or JSON Schema, then copy the result or download it as a file.
Note: Your CSV is read and analyzed in your browser. Nothing is sent to a server.
Limits to know before you run the SQL
- Types are inferred from the values in this one file. Review the output before you run it against a real database.
- VARCHAR(255), VARCHAR(2083), and DECIMAL(10,2) are fixed defaults. They are not sized from your longest string or your most decimal places.
- Integer columns map to INT, or to BIGINT when any value is larger than 2,147,483,647 in absolute value.
- Numbers with thousands separators or currency symbols, such as $1,234.50, are not recognized as numbers. Remove those characters first, or the column comes out as text.
- Dates are matched by shape only, so 03/04/2025 is accepted whether it means March 4 or April 3. Convert dates to YYYY-MM-DD before loading.
- Datetime columns map to DATETIME or TIMESTAMP, which carry no time zone. If your values end in Z or a UTC offset, adjust the type by hand.
- Only PRIMARY KEY, NOT NULL, and MySQL ENUM are generated. Indexes, foreign keys, defaults, and CHECK constraints are up to you.
Detected column types and their SQL equivalents
What each type means in this tool and the SQL type it produces.
| Detected type | Detection rule | MySQL | PostgreSQL | SQLite |
|---|---|---|---|---|
| Boolean | Every non-empty value is true/false, yes/no, or y/n (any case). Columns of 0 and 1 are read as integers. | TINYINT(1) | BOOLEAN | INTEGER |
| Integer | At least 95% are whole numbers with no leading zero. | INT (BIGINT above 2,147,483,647) | INTEGER (BIGINT above 2,147,483,647) | INTEGER |
| Decimal | At least 95% are integers or numbers with a decimal point, like 12.50. | DECIMAL(10,2) | NUMERIC(10,2) | REAL |
| Datetime | At least 90% match YYYY-MM-DD HH:MM[:SS] (also with T, fractional seconds, Z, or an offset), YYYY/M/D HH:MM, or M/D/YYYY h:mm with optional AM/PM. | DATETIME | TIMESTAMP | TEXT |
| Date | At least 90% match YYYY-MM-DD, YYYY/M/D, or M/D/YYYY. | DATE | DATE | TEXT |
| At least 90% look like [email protected]. | VARCHAR(255) | VARCHAR(255) | TEXT | |
| URL | At least 90% start with http:// or https://. | VARCHAR(2083) | TEXT | TEXT |
| Enum | At most 8 distinct values, fewer than 60% of the non-empty values are distinct, and at least 4 non-empty values. | ENUM('a','b',...) | VARCHAR(255) | TEXT |
| Text | Anything that matched none of the above. | VARCHAR(255) | VARCHAR(255) | TEXT |
Detection rules, thresholds, and edge cases
The details behind the type guesses, so you know when to trust them and when to override.
How each column is classified
For each column, empty cells are ignored and the remaining values are tested against the patterns in a fixed order. Integer and decimal pass at 95% matching values; datetime, date, email, and URL pass at 90%.
Values that do not match are not checked further. A column that is 96% integers and 4% words is still labeled integer, with a confidence of 96%.
What the confidence number tells you
Confidence is the share of non-empty values that matched the detected pattern. Boolean, enum, and text columns always show 100%, because they either match completely or are the fallback. A column with no values at all shows 0%.
Anything under 100% on a typed column means a few cells do not fit. Sort that column in a spreadsheet and look at the outliers before you load the file.
When a column becomes an enum
A column is suggested as an enum when it has 8 or fewer distinct values, those values are fewer than 60% of the non-empty cells, and there are at least 4 non-empty cells. Status, plan, and country-code columns usually qualify.
MySQL output uses ENUM with the values found in this file. PostgreSQL and SQLite output uses a plain text type, where you can add a CHECK constraint yourself.
ZIP codes, phone numbers, and other numeric-looking text
Whole numbers with a leading zero, like 02134, are treated as text so the zero is not lost. Phone numbers and account numbers without a leading zero still look like integers, and long ones push the column to BIGINT.
If you will never do math on a value, switch the column to Text with the Change type dropdown.
How the primary key suggestion works
A column is a candidate when it has no empty cells and no repeated values. Candidates named id, ending in _id, or named no are preferred. If none match, the first candidate in column order is used.
That can pick a column like email when it is the only unique one, so check that the suggestion is a real identifier.
Common mistakes with generated schemas
Running the generated VARCHAR(255) and DECIMAL(10,2) as they are
The lengths and precision are fixed defaults, not measured from your data. Longer text or values with more decimal places can fail to load or be cut off, depending on your database settings.
💡 See the solution▼
Trusting a date column that mixes formats
2025-01-05 and 1/5/2025 in the same column both match a date pattern, so the column is detected as a date. The import then fails or misreads some rows, because the database expects one format.
💡 See the solution▼
Keeping the suggested primary key without checking it
A column that is unique and has no empty cells in this file is only unique in this file. A new export can repeat values, and a column like email can change over time.
💡 See the solution▼
Storing phone numbers or account numbers as integers
Identifiers without a leading zero are detected as integers. They then lose formatting later, and long values can overflow INT.
💡 See the solution▼
Locking an enum to the values in one file
The ENUM list contains only the values found in this CSV. When a new status or plan shows up later, you have to alter the table before inserts will work.
💡 See the solution▼
Questions about type detection and SQL output
Q.How does the tool decide a column's data type?
A. It ignores empty cells and checks the remaining values against a fixed list of patterns in this order: boolean, integer, decimal, datetime, date, email, URL, enum, then text. Integer and decimal need at least 95% of values to match. Datetime, date, email, and URL need at least 90%. Boolean needs every value to be true/false, yes/no, or y/n in any letter case. The first check that passes sets the type.
Q.Can I change a type the tool got wrong?
A. Yes. Every row in the results table has a Change type dropdown with all nine types. The SQL, TypeScript, and JSON Schema output updates as soon as you pick a different one, and that column's confidence shows 100%.
Q.What does the confidence percentage mean?
A. It is the share of non-empty values that matched the detected pattern. Boolean, enum, and text columns always show 100%, and a column with no values at all shows 0% as text. A number below 100% means some cells do not fit the type, so check those rows before you load the data.
Q.How is the primary key chosen?
A. A column qualifies when it has no empty cells and every value is distinct. If several columns qualify, the tool prefers one named id, ending in _id, or named no. Otherwise it takes the first qualifying column. Treat it as a suggestion: a column can be unique in one file without being a good key.
Q.Which databases and output formats are supported?
A. CREATE TABLE for MySQL, PostgreSQL, and SQLite, plus a TypeScript interface and a JSON Schema (draft-07). Types are mapped per database. For example, a boolean becomes TINYINT(1) in MySQL, BOOLEAN in PostgreSQL, and INTEGER in SQLite.
Q.Is my CSV uploaded anywhere?
A. No. Your browser reads the file, and JavaScript on the page parses it and builds the output. The contents are not sent to a server, so files with customer data stay on your device.
Q.How are column names with spaces or special characters handled?
A. Names that are not plain letters, digits, and underscores are quoted in the output: backticks for MySQL and SQLite, double quotes for PostgreSQL, and quoted keys in TypeScript. You can also turn on Convert column names to snake_case, which changes First Name to first_name. Duplicate names get a numeric suffix, and empty headers become column_1, column_2, and so on.
Q.Why does my ZIP code column show up as text?
A. Whole numbers with a leading zero, such as 02134, are not treated as integers, because converting them would drop the zero. If almost all values have no leading zero, the column can still come out as integer. In that case, switch it to Text with the dropdown.
Q.Which delimiters and CSV formats can it read?
A. Comma, tab, or semicolon. The default is auto-detect, which counts each one in the first line and picks the most frequent. Quoted fields can contain delimiters, line breaks, and doubled quotes, and a UTF-8 byte order mark at the start of the file is removed.
Q.How does it decide between NULL and NOT NULL?
A. A column with at least one empty or whitespace-only cell stays nullable. A column with no empty cells gets NOT NULL, except the primary key, which gets PRIMARY KEY only.
Q.Does it create INSERT statements or load my data?
A. No. It generates the table definition only. After you create the table, use your database's import tool, such as LOAD DATA in MySQL, COPY in PostgreSQL, or .import in the SQLite shell.
Q.Can I use an Excel file?
A. Not directly. The tool reads CSV and TSV text. In Excel, choose Save As and pick CSV UTF-8, then upload that file.
Your feedback
makes this tool better.
Tell us which features you'd like, what should be fixed, or which new tool you'd like to see. An engineer reads every submission and uses it to guide development.