MeridianMERIDIAN

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

FlagTypeDefaultDescription
-f, --filepath—Input CSV, Parquet, JSON or NDJSON file (single-file mode). Mutually exclusive with --files.
--filespath—File listing input paths, one per line (batch mode). Requires --out-dir.
--out-dirpath—Output directory for batch mode. One output per input is written as <out_dir>/<stem>.<ext>.
-o, --outputstringplainOutput format: plain, json, csv, markdown, arrow, json-schema, datapackage
--sample-sizeinteger100Maximum values to sample per column
--delimitercharacterauto-detectCSV delimiter character
--no-header-hintflag—Disable column name header hints
--enum-thresholdinteger32Cardinality threshold for ENUM columns (0 disables ENUM, shows VARCHAR)
--statsflag—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, --verboseflag—Show additional detail and enable pipeline tracing
--no-validation-vetoflag—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.
--nominationspath—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.csv
FineType 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 analyzed

BROAD 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 json

The 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.json

This 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.json

The 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.json

This 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 profile decides each column
  • validate — validate against the exported schema and optionally materialise a typed table
  • infer — classify individual values
  • taxonomy — browse the semantic type taxonomy
  • Quick Start — full walkthrough from install to first profile

On this page