Skip to content

Repository files navigation

DX — Universal Structured Data CLI

One binary. One syntax. Every format.

DX replaces jq, yq, dasel, miller, xsv, and custom scripts with a single, fast Rust binary. Query, convert, diff, validate, and transform data across 16 formats with one consistent syntax.

CICrates.ioLicense: MIT OR Apache-2.0

Why DX?

ProblemBeforeWith DX
Query JSONjq '.users[] | select(.age > 25)'dx query data.json '.users[] | select(.age > 25)'
Query YAMLyq '.database.host' config.yamldx query config.yaml '.database.host'
Convert YAML to TOMLyq -o json | python3 -c "..."dx convert config.yaml --to toml
Diff two configsdiff <(yq ...) <(toml ...)dx diff staging.yaml prod.toml
Validate against schemaajv validate -s schema.json -d data.jsondx validate data.json --schema schema.json
CSV field extractioncsvcut -c name,email data.csvdx pick data.csv name email

One tool. Every format. No more tool-per-format chaos.

How DX Compares

FeaturejqyqdaselmillerDX
JSONYesYesYesYesYes
YAML-YesYes-Yes
TOML-YesYes-Yes
CSV--YesYesYes
XML-YesYes-Yes
NDJSONYes--YesYes
MessagePack / CBOR / BSON----Yes
INI / HCL / Properties----Yes
JSON5 / RON / Plist----Yes
Query String----Yes
Cross-format convert-PartialYes-Yes
Cross-format diff----Yes
Schema validation----Yes
Schema inference----Yes
Total formats144316

Quick Start

Installation

From crates.io:

cargo install dx-cli

From prebuilt binaries:

Download the latest release for your platform from GitHub Releases.

Homebrew (macOS/Linux):

brew install aronriley24/tap/dx

From source:

git clone https://github.com/aronriley24/Data-eXchange.git
cd Data-eXchange
cargo build --release
# Binary at target/release/dx

Verify installation

dx --version
dx --help

Usage

Query — Extract and transform data

# Simple field access
dx query config.yaml '.database.host'# => "localhost"# Array filtering
dx query users.json '.[] | select(.age > 25)'# Object construction
dx query users.json '.[] | {name: .name, email: .email}'# Aggregation
dx query sales.json '.[] | sum'# Sort and group
dx query users.json '. | sort_by(.age) | reverse'
dx query users.json '. | group_by(.active)'# String operations
dx query users.json '.[] | .name | upper'# Pipe chains — same syntax works on any format
dx query users.csv '.[] | select(.active) | {name: .name, age: .age} | sort_by(.age)'

Convert — Transform between any formats

# Text formats
dx convert config.yaml --to toml
dx convert users.json --to csv
dx convert settings.ini --to yaml
dx convert infrastructure.hcl --to json
# Binary formats (output requires -o or piping)
dx convert data.json --to msgpack -o data.msgpack
dx convert data.msgpack --to json
# CSV options
dx convert data.csv --to json # with type inference
dx convert data.csv --to json --csv-no-infer # keep as strings
dx convert data.tsv --to json --csv-delimiter '\t'# TSV support# JSONC is transparent — comments and trailing commas just work
dx convert config.jsonc --to yaml
# Stdin piping
cat data.json | dx convert - --to yaml
# NDJSON streaming
dx convert logs.ndjson --to json --stream

Diff — Structural comparison across formats

# Compare two files (any format mix)
dx diff config.json config_modified.json
# Cross-format diff — this just works
dx diff staging.yaml prod.toml
# Keys only (hide values)
dx diff old.json new.json --keys-only
# Ignore array ordering
dx diff expected.json actual.json --ignore-order
# Machine-readable JSON output
dx diff old.json new.json --output-format json

Validate — JSON Schema validation

# Validate data against a schema
dx validate users.json --schema user_schema.json
# Verbose error output
dx validate data.json --schema schema.json --verbose
# Machine-readable JSON errors
dx validate data.json --schema schema.json --output-format json
# Exit code 0 = valid, 1 = invalid
dx validate data.json --schema schema.json &&echo"Valid!"

Schema — Infer JSON Schema from data

# Infer schema from data
dx schema users.json
# Specify JSON Schema draft version
dx schema users.json --draft 2020-12

Pick — Quick field extraction

# Extract specific fields
dx pick users.json name email
# => [{"name":"Alice","email":"alice@example.com"}, ...]# Nested field access
dx pick config.yaml database.host database.port

Count — Element counting

# Count array elements
dx count users.json
# => 5# Count CSV rows (excluding header)
dx count data.csv
# Count object keys
dx count config.yaml
# Count at a nested path
dx count data.json '.users'

Flatten / Unflatten — Dot-notation transformation

# Flatten nested data
dx flatten config.yaml
# => {"database.host":"localhost","database.port":5432,...}# Custom separator
dx flatten config.yaml --separator '/'# Unflatten back to nested
dx unflatten flat.json

Merge — Deep merge files

# Merge two configs (later values win)
dx merge base.yaml overrides.yaml
# Merge multiple files (left to right)
dx merge base.toml local.toml production.toml
# Array strategies
dx merge a.json b.json --arrays concat # concatenate arrays (default)
dx merge a.json b.json --arrays replace # later array replaces
dx merge a.json b.json --arrays union # concat + deduplicate

Format — Pretty-print data

# Pretty-print JSON
dx fmt data.json
# Format in-place
dx fmt config.json --in-place
# Compact output
dx fmt data.json --compact
# Custom indentation
dx fmt data.json --indent 4

Supported Formats

DX supports 16 formats — 13 text and 3 binary:

FormatExtensionsReadWriteNotes
JSON.json, .jsoncYesYesJSONC (comments + trailing commas) handled transparently
YAML.yaml, .ymlYesYes
TOML.tomlYesYesNo null type; keys sorted alphabetically
CSV.csv, .tsvYesYesType inference, custom delimiters
NDJSON.ndjson, .jsonlYesYesStreaming support with --stream
XML.xmlYesYes
JSON5.json5Yes-Parse-only (emit as JSON instead)
RON.ronYesYesRusty Object Notation
Plist.plistYesYesApple property lists
MessagePack.msgpack, .mpYesYesBinary — requires -o or pipe
CBOR.cborYesYesBinary — requires -o or pipe
BSON.bsonYesYesBinary — requires -o or pipe
INI.iniYesYesSectioned config files
HCL.hcl, .tfYesYesHashiCorp Configuration Language
Query String.qsYesYesURL-encoded key-value pairs
Properties.propertiesYesYesJava properties files

Format Auto-Detection

DX automatically detects the input format from:

  1. --from flag (highest priority)
  2. File extension
  3. Content sniffing (JSON: {/[, YAML: ---, TOML: [section], etc.)

Global Flags

FlagDescription
--from <fmt>Override input format detection
--to <fmt>Override output format
--prettyForce pretty-printed output
--compactForce compact output (no whitespace)
--rawRaw string output (no quotes)
--linesOutput each array element on its own line
--no-colorDisable colored output
--color=alwaysForce colored output (even in pipes)
-o <file>Write output to file instead of stdout

Query Language

DX uses a jq-inspired query language that works identically across all 16 formats.

Operators

OperatorDescriptionExample
.Identity (current value)dx query data.json '.'
.fieldField access.name
.field?Optional field (null if missing).maybe_field?
.[n]Array index.[0]
.[n:m]Array slice.[1:3]
.[]Array iteration.[]
|Pipe.users | .[] | .name
+, -, *, /, %Arithmetic.price * .quantity
==, !=, <, >, <=, >=Comparison.age > 25
=~Regex match.email =~ "@example\\.com$"
and, or, notBoolean logic.active and .age > 18

Built-in Functions (31)

CategoryFunctions
Accesslength, keys, values, type, has(key)
Transformpick(f1,...), omit(f1,...), map(expr), flat_map(expr), flatten
Sort/Groupsort_by(expr), group_by(expr), unique_by(expr), reverse
Aggregatesum, min, max, avg, first, last
Stringupper, lower, trim, split(d), join(d), contains(s), starts_with(s), ends_with(s)
Typeto_int, to_float, to_string
Logicnot (also prefix operator)
Selectionselect(condition)

Output Formats

# Default: format-appropriate output
dx query data.json '.users'# Table view (arrays of objects become ASCII tables)
dx query data.json '.users' --to table
# Raw strings (no quotes)
dx query data.json '.name' --raw
# One element per line (shell-friendly)
dx query data.json '.names' --lines

Shell Completions

# Bash
dx completions bash >~/.local/share/bash-completion/completions/dx
# Zsh
dx completions zsh >~/.zfunc/_dx
# Fish
dx completions fish >~/.config/fish/completions/dx.fish
# PowerShell
dx completions powershell > dx.ps1
# Elvish
dx completions elvish > dx.elv

Exit Codes

CodeMeaning
0Success
1Validation failure (dx validate only)
2Runtime error (parse failure, I/O error, etc.)

Limitations

  • Binary formats (MessagePack, CBOR, BSON) are supported for all commands that read input when the format is set via --from or a recognized file extension (e.g. .msgpack). Use --from msgpack for stdin or when the extension is ambiguous.
  • JSON5 is parse-only (no emit); use --to json or another format for output.
  • Pickle (Python serialization) is unsafe for untrusted data; see SECURITY.

Architecture

DX is built as a Cargo workspace with 6 crates:

dx/
├── dx-core # DxValue IR, error types, Format enum, traits
├── dx-formats # Parsers/emitters for all 16 formats
├── dx-query # jq-inspired query language (lexer, parser, evaluator)
├── dx-diff # Structural diff engine
├── dx-validate # JSON Schema validation + inference
└── dx-cli # CLI binary (presentation, clap, colored output)

Design Principles

  • Single IR: All formats parse to DxValue, a unified intermediate representation. Queries, diffs, and validation operate on DxValue, never on raw format data. This means cross-format operations (like dx diff staging.yaml prod.toml) work automatically.
  • Crate boundaries: Library crates produce structured data. Only dx-cli handles presentation (colors, tables, terminal detection).
  • Integer/Float distinction: DxValue preserves the difference between 42 (integer) and 42.0 (float) through all operations.
  • Key ordering: Uses IndexMap to preserve insertion order across all formats that support it.
  • Factory dispatch: parser_for() / emitter_for() centralize format dispatch — no N x M match blocks.

Building from Source

git clone https://github.com/aronriley24/Data-eXchange.git
cd Data-eXchange
cargo build --release
# The binary is at target/release/dx
./target/release/dx --version
# Run all 1128 tests
cargo test --workspace
# Run clippy (zero warnings required)
cargo clippy --workspace -- -D warnings
# Format check
cargo fmt --all -- --check
# Supply chain audit
cargo deny check

Contributing

Contributions are welcome! See CONTRIBUTING.md for:

  • How to run checks (fmt, clippy, tests, cargo deny)
  • Architecture and crate boundaries
  • Code style and where to add tests

Check the issues for "good first issue" labels if you're looking for a place to start.

License

Licensed under either of:

at your option.

About

dx — universal structured-data CLI (JSON, YAML, TOML, CSV and more)

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages