What the CSV Schema Profiler does
This profiler reads a CSV file in your browser and reports, for every column, the type its values actually follow, how many are empty, how many distinct values there are, the range, the text lengths and the most common shapes - then drafts a CREATE TABLE statement from what it found. It is the check to run before you import a file into a database, hand it to a pipeline, or trust the column names someone gave you.
Nothing is uploaded. The file is parsed with an RFC 4180 reader in this tab, and when you profile a sample instead of the whole file the result says so.
How to use it
- Drop a CSV, choose one, or paste rows into the box. Files up to 50 MB and 200,000 data rows are read; anything beyond that is not, and the page tells you.
- Leave the delimiter on automatic unless the detection is wrong - it compares comma, semicolon, tab and pipe across the first twenty lines. Untick the header box if the first row is data.
- Choose whether to profile every row or only the first 10,000 or 50,000. A sample is quicker on big files, but a rare bad value later in the file will not be seen.
- Select Profile columns. Read the findings first - exceptions, leading zeros, stray spaces - then the table, then open a column's details for its commonest values and shapes.
- Copy the suggested schema, or download the profile as JSON or CSV to keep alongside the file.
Reading the results
Type is decided from the text alone. A column is typed when every non-null value matches, or when at least 95% do; the remaining values are counted as exceptions and flagged, because they are exactly what makes an import fail on row 48,211.
Nulls include empty cells and a fixed list of tokens (null, NA, N/A, none, NaN, nil, #N/A). That list is a convention, not a standard - RFC 4180 has no idea of null - so check it matches how your file was produced.
Distinct counts are exact up to 100,000 values per column; above that the figure is shown as a lower bound. A column whose non-null values are all different is marked unique - a candidate key, not a proven one.
Shapes replace digits with 9 and letters with a or A, so LS1 4AP becomes AA9 9AA. Several shapes in a column that should have one - postcodes, phone numbers, order references - usually means mixed sources or hand-typed data.
Worked example: profiling a 12-row orders export
Load the Orders export example: 12 orders with nine columns. order_id runs from 10001 to 10012 with 12 distinct values, so it is an integer and unique. total_gbp mixes 250.00 and 7.25; its values add up to 806.58, so the mean is 806.58 / 12 = 67.215, and with three integer digits and two decimals it becomes NUMERIC(5, 2).
shipped_at is an ISO 8601 timestamp with 3 empty cells - the three orders that are pending or cancelled - so it is typed as a datetime and left nullable. coupon is empty on 8 of 12 rows and holds only 2 distinct codes, with SPRING10 used three times.
status has three values (shipped nine times, pending twice, cancelled once). The profiler reports it as text; whether it should become an enum or a lookup table is your decision, not the tool's.
Why a profile comes before an import
Most CSV import failures are not parsing failures. The file parses; then one value in a numeric column says n/a, a date column switches from 2024-03-01 to 01/03/2024 halfway down, or an account number loses its leading zeros because it was loaded as an integer. A profile shows each of these before the load rather than after.
Leading zeros deserve special attention. 00917 is a perfectly good integer pattern, but if it is a member code, a postcode fragment or a phone prefix, storing it as a number turns it into 917. The profiler counts integer-looking values with leading zeros and suggests a text column when it finds them.
How the suggested schema is built
Integers become INTEGER, or BIGINT when a value falls outside the 32-bit range. Decimals become NUMERIC(p, s) sized from the widest integer part and the longest fraction seen. ISO dates become DATE, timestamps TIMESTAMP, UUIDs UUID, and text VARCHAR(n) with n set to the longest value (or TEXT beyond 255 characters). A column with no nulls gets NOT NULL.
These are PostgreSQL type names and a starting point. The sizes fit the data you profiled, not the data you will receive next month, so widen them where you expect growth, and add keys, constraints and indexes yourself.
Limitations: what the result does not prove
- Types come from pattern matching on text. A column of integers may still be an identifier that should never be summed, and a text column may be a date in a format the profiler does not guess at, such as
03/04/2024. - A sample profile only describes the rows it read. The first 10,000 rows of an export are often the oldest and cleanest.
- Unique in this file does not mean unique by design. A key constraint belongs in your schema, backed by how the data is generated.
- The file must fit in the tab's memory. Very wide or very large files may be slow on a phone; the 50 MB and 200,000-row limits exist for that reason.
Privacy: where your data goes
Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics. Session recording and tag-manager scripts are switched off on this page.
Standards and sources
- RFC 4180 CSV - checked 19 Sep 2026
- ISO 8601 date and time format (ISO overview)
- PostgreSQL documentation - Data types
Frequently asked questions
How does the profiler decide a column is a date?
Only ISO 8601 values count: 2024-05-01, or a date and time such as 2024-05-01T10:30:00Z. Each date is also checked against the calendar, so 2023-02-29 stays text. Formats like 05/01/2024 are left as text on purpose, because they read differently in the UK and the US.
Why is a column of emails reported as text?
Because fewer than 95% of its non-null values looked like email addresses. Open the column details to see the type counts - often one or two values such as name(at)example.com or an address with a trailing space are enough to show it is not clean.
Does profiling a sample give different results from the whole file?
It can. Minimums, maximums, distinct counts and null counts only reflect the rows that were read, and a single bad value outside the sample will not be flagged. The stats tile states which was used, so a shared profile cannot be mistaken for a full one.
What does a shape like AA9 9AA mean in the column details?
It is the value with digits replaced by 9, capital letters by A and lower-case letters by a; other characters are kept and non-ASCII letters become an asterisk. Counting shapes is a quick way to spot mixed formats in codes, postcodes and phone numbers.
Can I use the suggested CREATE TABLE statement directly?
Treat it as a draft. The types and lengths fit the rows you profiled, the names are quoted only when they need to be, and there are no keys or indexes. Review it, widen lengths where the data will grow, and run it through your normal migration process.
Which delimiters and encodings are supported?
Comma, semicolon, tab and pipe, detected automatically or chosen by hand. Quoted fields may contain delimiters, doubled quotes and line breaks as RFC 4180 describes. Files are read as UTF-8, and a leading byte-order mark is ignored.
Is my file sent anywhere while it is profiled?
No. The file is read with the browser's FileReader and every calculation happens in this tab. You can disconnect from the network after the page loads and the profiler still works.
Last reviewed by the A2Z.Tools team against the sources listed above.