dasel 3.11.2 is a query and conversion tool for JSON, YAML, TOML, XML and CSV. The Windows build is a single 10756608-byte exe, and version 3 broke the syntax that version 2 used.

The problem it solves is reading one field out of a 1 MB JSON file without opening an editor or writing a script. Piping through jq works for JSON, but the same file often arrives as YAML.

I fed a 1072296-byte JSON array of 10000 records through four operations, and the numbers below include the cost of parsing all of it for every single query.

One 10756608-byte exe

Single file, no installer, no runtime. It reads from standard input and writes to standard output, so it composes with anything.

ItemValueNote
dasel.exe10756608 bytesdasel_windows_amd64.exe
Version output427 bytesA usage block, not just a number
Subcommands5query, version, interactive, completion, man
Input size used here1072296 bytes10000 records

--version prints a usage block

427 bytes come back from dasel --version, because the flag is not recognised as a version switch in 3.x. The real one is the version subcommand.

It reads stdin by default

There is no -f file flag in 3.x. Input arrives on stdin and formats are chosen with -i and -o, which is why every example below starts with a pipe.

Four operations on 1072296 bytes

Same input, four outputs. Times are medians of three runs including process start.

OperationTimeOutput bytes
--root --compact318 ms932298
--root (pretty JSON)359 ms2552299
--root -o yaml540 ms1102296
small object, one key167 ms2 bytes

Pretty printing triples the output

932298 bytes compact becomes 2552299 bytes with indentation, 2.7 times larger, for 41 ms more. The cost is output, not parsing.

YAML is the slowest at 540 ms

YAML output is 1102296 bytes, close to the 1072296-byte input, but it takes 181 ms longer than pretty JSON. Serialising YAML is more work than emitting indented JSON.

Every query parses the whole file

A single key from a small object takes 167 ms, and the same order of magnitude applies to any selector because the entire document is parsed before the query runs.

InputOperationTime
32-byte objectread key a167 ms
1072296-byte array--root --compact318 ms

167 ms is the floor

A 32-byte input still costs 167 ms, so the process load and format setup dominate anything small. For a shell loop over hundreds of files, that floor multiplies.

dasel 3.11.2 printing a JSON array of four records with syntax colour: keys in blue, strings in yellow, numbers in white, booleans in red, two-space indentation

Parsing 1 MB adds about 150 ms

Going from 32 bytes to 1072296 bytes moved the compact run to 318 ms, so the actual parse of a megabyte of JSON is in the same range as the fixed cost rather than an order of magnitude above it.

The 3.x syntax is not the 2.x syntax

Selectors that worked in 2.x fail in 3.x with a parse error, and the error message names the token rather than the fix.

SelectorResult in 3.11.2
.afailed to parse: unexpected token "." at position 0
aworks, prints 1
[0].nameunexpected type: expected map, got array
--rootworks, prints the whole document

The leading dot has to go

dasel -i json '.a' is a parse error in 3.x; dasel -i json 'a' returns 1. Any script written against 2.x needs every selector rewritten.

Array indexing is not [0]

On an array root, [0].name reports "expected map, got array", so the bracket form does not index into an array the way it reads. Reaching into an array needs a different expression, and --root is the reliable way to get everything out.

YAML costs 18% more bytes

The same 10000 records become 932298 bytes as compact JSON and 1102296 bytes as YAML, so the human-readable form is 170000 bytes larger for identical content.

Output formatBytesVersus compact JSON
compact JSON932298baseline
pretty JSON25522992.7 times larger
YAML110229618% larger

YAML sits between the two JSON forms

YAML drops the braces and quotes that pretty JSON repeats on every line, so it lands 18% above compact and 57% below pretty. For a config file a human edits, that is the right trade.

Per record the gap is 17 bytes

Across 10000 records the difference is 170000 bytes, which is 17 bytes per record. That is roughly the `- ` list marker and one line break per entry.

Five subcommands in one exe

The help screen lists query, version, interactive, completion and man. Only the first is needed for the operations above.

SubcommandPurpose
queryDefault; runs a selector against stdin
versionPrints the version, unlike the --version flag
interactiveREPL session, marked alpha
completionShell completion script for bash or zsh
manGenerates a man page

interactive is still alpha

The REPL is labelled alpha in its own help text, so it is not the path to build tooling on. Every measurement above used the non-interactive query path, which is the stable surface.

completion and man are for setup

Neither affects runtime. completion emits a shell script and man emits documentation, both useful once and then irrelevant.

What it is good for

Converting between formats and pulling values out of a document you can see the shape of, on a machine where installing jq and yq separately is friction.

TaskFitWhy
JSON to YAML in one stepHigh540 ms for 1 MB, one flag pair
Inspecting an unfamiliar fileHigh--root pretty prints with syntax colour
Scripted field extractionMedium167 ms floor per call, syntax changed in 3.x
Replacing jq in existing scriptsLowSelectors were rewritten between major versions

Pair it with a format you already trust

For JSON-only work, jq has a stable selector language and a much smaller fixed cost. dasel earns its place when the same pipeline has to touch YAML, TOML or XML.

Licence and cost

MIT. Free for personal and commercial use, source on GitHub, written in Go. The Windows build is one exe with no installer and no registry writes.