profile
Profile a CSV, Parquet, JSON or NDJSON file with finetype profile, detecting the semantic type of every column, then export a JSON Schema or a Data Package.
Scan a CSV, Parquet, JSON or NDJSON file and detect the semantic type of every column. profile is the fastest way to understand what your data contains — run it before writing any queries.
Usage
finetype profile [OPTIONS] --file <FILE>Options
| Flag | Type | Default | Description |
|---|---|---|---|
-f, --file | path | — | Input CSV, Parquet, JSON or NDJSON file (single-file mode). Mutually exclusive with --files. |
--files | path | — | File listing input paths, one per line (batch mode). Requires --out-dir. |
--out-dir | path | — | Output directory for batch mode. One output per input is written as <out_dir>/<stem>.<ext>. |
-o, --output | string | plain | Output format: plain, json, csv, markdown, arrow, json-schema, datapackage |
--sample-size | integer | 100 | Maximum values to sample per column |
--delimiter | character | auto-detect | CSV delimiter character |
--no-header-hint | flag | — | Disable column name header hints |
--enum-threshold | integer | 32 | Cardinality threshold for ENUM columns (0 disables ENUM, shows VARCHAR) |
--stats | flag | — | Attach observed-data constraints to JSON Schema output (minLength/maxLength, minimum/maximum, the closed enum keyword, x-finetype-null-rate, x-finetype-cardinality). Requires -o json-schema. |
-v, --verbose | flag | — | Show additional detail and enable pipeline tracing |
--no-validation-veto | flag | — | Disable validation-as-veto (on by default). By default a prediction becomes unknown when fewer than half of the column's sample values pass that type's own validation, scoped to audited-safe types; other types get an advisory flag. Pass this to keep the raw prediction. |
--nominations | path | — | JSON file declaring what columns are, instead of letting Finetype guess. A nominated column keeps its declared label, publishes no confidence, and is skipped by the validation veto. |
Examples
These examples read contacts.csv, the quick start's sample file.
Profile a CSV file
finetype profile -f contacts.csvFineType Column Profile — "contacts.csv" (12 rows, 6 columns)
════════════════════════════════════════════════════════════════════════════════
COLUMN TYPE BROAD CONF
──────────────────────────────────────────────────────────────────────────────
id representation.identifier.increment BIGINT 98.5% [numeric_sequential_detection]
name identity.person.full_name VARCHAR 96.0%
email identity.person.email VARCHAR 63.8% ⚑ low
created_at datetime.timestamp.iso_8601 TIMESTAMP 100.0%
ip_address technology.internet.ip_v4 VARCHAR 100.0% [ipv4_detection]
amount representation.numeric.decimal_number DOUBLE 60.0% [amount_bare_number_veto:amount] ⚑ low
6/6 columns typed, 12 rows analyzedBROAD is the DuckDB storage type for the column. CONF is the confidence, followed in brackets by the rule, guard or header hint Finetype applied to the column, and by the quality band where it is not high (~ medium, ⚑ low). The Finetype overview explains the bands.
Profile with JSON output
finetype profile -f contacts.csv -o jsonThe output is an object with file, rows and a columns array. Each entry carries the semantic type, the broad_type (DuckDB storage type), the confidence, a quality_band, null counts, the validation_pass_rate, and the transform expression used to cast the column. The first entry:
{
"broad_type": "BIGINT",
"column": "id",
"confidence": 0.98473060131073,
"disambiguation_applied": true,
"disambiguation_rule": "numeric_sequential_detection",
"is_generic": true,
"non_null": 12,
"null": 0,
"quality_band": "high",
"samples_used": 12,
"transform": "CAST({col} AS BIGINT)",
"type": "representation.identifier.increment",
"validation_pass_rate": 1.0
}A column in the low band also carries runner_up, the second-best type, or null where there is none.
Pipe to jq to pull out just the types:
finetype profile -f contacts.csv -o json | jq '.columns[].type'"representation.identifier.increment"
"identity.person.full_name"
"identity.person.email"
"datetime.timestamp.iso_8601"
"technology.internet.ip_v4"
"representation.numeric.decimal_number"Export a JSON Schema for the whole file
finetype profile -f contacts.csv -o json-schema > schema.jsonThis writes a JSON Schema describing every column, the schema you pass to validate. The email property:
"email": {
"maxLength": 254,
"minLength": 5,
"pattern": "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$",
"type": "string",
"x-finetype-label": "identity.person.email",
"x-finetype-pii": true
}Add --stats to attach observed-data constraints:
finetype profile -f contacts.csv -o json-schema --stats > schema.jsonThe email property then carries the lengths seen in the file in place of the type's bounds, with the null rate and the number of distinct values:
"email": {
"maxLength": 19,
"minLength": 11,
"pattern": "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$",
"type": "string",
"x-finetype-cardinality": 12,
"x-finetype-label": "identity.person.email",
"x-finetype-null-rate": 0.0,
"x-finetype-pii": true
}A bounded column also carries x-finetype-enum, the set of values seen, by default and with or without --stats. It describes the sample and is not a closed constraint.
Export a Frictionless Data Package
finetype profile -f contacts.csv -o datapackage > datapackage.jsonThis writes a Frictionless Data Package descriptor (v2.0): a Data Resource (with path, format, mediatype, bytes and a sha256 hash) around a Table Schema whose field type/format come from Finetype's detection. The descriptor, with only the email field of the six:
{
"$schema": "https://datapackage.org/profiles/2.0/datapackage.json",
"created": "2026-11-03T06:01:49Z",
"name": "contacts",
"resources": [
{
"bytes": 853,
"encoding": "utf-8",
"format": "csv",
"hash": "sha256:e5c36957e666a50c8853eb457262665f0f10587ae5067ff9a5b0fbf65752ff78",
"mediatype": "text/csv",
"name": "contacts",
"path": "contacts.csv",
"schema": {
"fields": [
{
"constraints": {
"maxLength": 254,
"minLength": 5,
"pattern": "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$|^[a-z]{3}-[a-z]{2}-[a-z]{5}$"
},
"format": "email",
"name": "email",
"type": "string",
"x-finetype-confidence": 0.6383,
"x-finetype-label": "identity.person.email",
"x-finetype-pattern-fit": {
"canonical": "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$",
"outcome": "widened"
},
"x-finetype-pii": true
}
]
}
}
]
}Every field maps to a standard Frictionless type/format, and Finetype's detail rides along as x-finetype-* properties. Here x-finetype-pattern-fit records that the field's pattern was widened from the type's canonical one: the alternative added at its end, ^[a-z]{3}-[a-z]{2}-[a-z]{5}$, matches the file's not-an-email.
A Data Package describes a dataset; to apply the typed cast, use the json-schema output with validate.
See also
- Accuracy in the Finetype overview — the measured figure, how to read the confidence and quality bands, and how
profiledecides each column validate— validate against the exported schema and optionally materialise a typed tableinfer— classify individual valuestaxonomy— browse the semantic type taxonomy- Quick Start — full walkthrough from install to first profile
infer
Classify text into semantic types with finetype infer: a single value, a file of values, or a stream of column batches. Its usage, options and output formats.
validate
Validate a CSV or Parquet file against a JSON Schema with finetype validate: check only, or materialise a typed DuckDB table in one pass, with its exit codes.