Dasel (Data-Select) is a CLI tool for querying, modifying, and converting structured data files using a consistent query syntax across formats.
Docs are bundled in
references/. Read them when you need deeper detail on a topic.
CLI basics
# Read from stdin, specify input format
echo '{"name":"Tom"}' | dasel -i json 'name'
# => "Tom"
# Read from a file via stdin redirection
dasel -i yaml 'database.host' < config.yaml
Convert formats: read JSON, output YAML
cat data.json | dasel -i json -o yaml
Output the whole document (needed when modifying)echo '{"a":1}' | dasel -i json --root 'a = 2'
=> {"a": 2}
**Key flags:**
| Flag | Short | Purpose |
|------|-------|---------|
| `--in FORMAT` | `-i` | Input format (json, yaml, toml, xml, csv, hcl, ini) |
| `--out FORMAT` | `-o` | Output format |
| `--root` | | Output the full document, not just the selected value |
| `--var name=fmt:file:path` | | Pass a file as a named variable |
| `--read-flag key=val` | | Parser-specific read options |
| `--write-flag key=val` | | Parser-specific write options |
| `--config PATH` | `-c` | Path to dasel config file (default: `~/dasel.yaml`) |
| `--unstable` | | Enable unstable/experimental features |
---
## Query syntax
Queries are dot-chained **accessors** and **function calls**, terminated with `;` when using multiple statements.
Access nested fields
user.address.city
Array index (zero-based)users[0].name
Range sliceusers[0:4]
Assign (modifies the value in the document)user.name = "Alice"
Variables - $root is stdin, $this is current element$root.users.filter(active == true).map(name)
**Multi-statement queries** (use `;` to separate, last statement is the output):
$active = $root.users.filter(active == true); $active.map(name)
### Environment variables
```bash
GREETING=hello NAME=tom dasel '$GREETING + " " + $NAME'
# => "hello tom"
Common patterns
Read a value
echo '{"foo":{"bar":"baz"}}' | dasel -i json 'foo.bar'
# => "baz"
Modify a value (output full document)
echo '{"foo":"old"}' | dasel -i json --root 'foo = "new"'
# => {"foo": "new"}
Edit a file in place
dasel -i yaml --root 'server.port = 9090' < config.yaml > config.yaml.tmp \
&& mv config.yaml.tmp config.yaml
Note: there is no
-fflag for data files in v3. Always use stdin (< fileorcat file |). Note: always go via a temp file — bash truncates the target before dasel reads it.
Filter an array
echo '{"users":[{"name":"Alice","active":true},{"name":"Bob","active":false}]}' \
| dasel -i json 'users.filter(active == true).map(name)'
# => ["Alice"]
Map / transform
echo '[1,2,3]' | dasel -i json 'map($this * 2)'
# => [2, 4, 6]
Modify elements in place with each
echo '[1,2,3]' | dasel -i json 'each($this = $this + 1)'
# => [2, 3, 4]
Default / coalesce
# Fall back to a default if path missing
dasel -f config.yaml 'server.timeout ?? 30'
Conditional
dasel -f data.json 'if(count > 5) { "many" } else { "few" }'
Recursive descent — find all values by key
# All values with key "name" at any depth
dasel -f data.json '..name'
# All values at any depth
dasel -f data.json '..*'
Predicate-based deep search
dasel -f data.json 'search(has("id") && has("name"))'
Format conversion
cat file.json | dasel -i json -o yaml
cat file.yaml | dasel -i yaml -o toml
Build a new object
echo '{"first":"Tom","last":"Wright"}' \
| dasel -i json '{"fullName": first + " " + last}'
Spread operator
# Merge objects
echo '{"a":1}' | dasel -i json '{$this..., "b": 2}'
# => {"a":1,"b":2}
# Append to array
echo '[1,2,3]' | dasel -i json '[$this..., 4, 5]'
# => [1,2,3,4,5]
Supported formats
| Format | Read | Write | Notes |
|---|---|---|---|
| json | ✓ | ✓ | |
| yaml | ✓ | ✓ | |
| xml | ✓ | ✓ | See --read-flag xml-mode=structured |
| csv | ✓ | ✓ | All values as strings; --read-flag csv-delimiter=; |
| hcl | ✓ | ✓ | --read-flag hcl-block-format=array |
| toml | ✓ | ✓ | Generally working; unsorted maps |
| ini | ✓ | ✓ | Basic sections + key values only |
Key functions
| Function | Description | Example |
|---|---|---|
filter(pred) |
Filter array by predicate | arr.filter($this > 1) |
map(expr) |
Transform each element | arr.map($this * 2) |
each(expr) |
Iterate and modify in place | arr.each($this = $this+1) |
search(pred) |
Recursive predicate search | search(has("key")) |
has(key) |
Check key/index exists | has("name") |
len(x) |
Length of array/string | len($root.items) |
keys(obj) |
Keys of a map | keys($root.config) |
add(a,b) |
Add / concatenate | add(1, 2) |
join(arr, sep) |
Join array to string | join(tags, ",") |
replace(str,old,new) |
String replace | replace(name,"_"," ") |
sortBy(key) |
Sort array of objects | users.sortBy(name) |
reverse(arr) |
Reverse array | reverse(items) |
min(arr) / max(arr) |
Min/max of numbers | min(scores) |
sum(arr) |
Sum numbers | sum(prices) |
toString(x) |
Convert to string | toString(id) |
toInt(x) |
Convert to int | toInt(count) |
typeOf(x) |
Type name | typeOf(value) |
parse(fmt, str) |
Parse a string as a format | parse("json", raw) |
readFile(path) |
Read a file | readFile("x.json") |
base64e(str) |
Base64 encode | base64e(token) |
base64d(str) |
Base64 decode | base64d(encoded) |
For full function signatures and examples, see
references/functions.md.
Reference files
| File | When to read |
|---|---|
references/syntax.md |
Deep dive: types, arrays, objects, conditionals, spread, coalesce, branches, regex, recursive descent |
references/functions.md |
All function signatures with examples |
references/input-output.md |
Stdin/stdout, file editing, variables, format flags |
Tips
- Always use
--rootwhen modifying data and wanting the full document back. - Use
;to write multi-statement queries for clarity. $rootis the stdin document;$thisis the current element inside functions.- For in-place file edits, always redirect to a
.tmpfile first, thenmv. - The ternary operator (
? :) is not yet implemented — useif/elseform instead. branchis unstable — requires--unstableflag.