Introduction
Note
Dasel V3 was released in December 2025. Please raise any issues on GitHub.

Dasel (short for Data-Select) is a command-line tool and library for querying, modifying, and transforming data structures such as JSON, YAML, TOML, XML, and CSV.
It provides a consistent , powerful syntax to traverse and update data - making it useful for developers, DevOps, and data wrangling tasks.
Features
- Multi-format support: JSON, YAML, TOML, XML, CSV, HCL (with more planned).
- Unified query syntax: Access data in any format with the same selectors.
- Query & search: Extract values, lists, or structures with intuitive syntax.
- Modify in place: Update, insert, or delete values directly in structured files.
- Convert between formats: Seamlessly transform data from JSON → YAML, TOML → JSON, etc.
- Script-friendly: Simple CLI integration for shell scripts and pipelines.
- Library support: Import and use in Go projects.
Installation
Homebrew
The easiest way to get your hands on the latest version of dasel is to use homebrew:
brew install dasel
Docker
Run dasel in docker using the image ghcr.io/tomwright/dasel.
Usage
Run the docker image, passing in a dasel command with the executable excluded.
$ echo '{"name": "Tom"}' | docker run -i --rm ghcr.io/tomwright/dasel:latest -i json 'name'
"Tom"
Versioning
New image versions are built and pushed automatically as part of the CI/CD pipeline in Github actions.
| Tag | Description |
|---|---|
latest | The latest release version. |
development | The latest build from master branch. |
v*.*.* | The specified dasel release. E.g. v2.0.0. |
ASDF
Using asdf-vm and the asdf-dasel plugin.
asdf plugin add dasel https://github.com/asdf-community/asdf-dasel.git
asdf list all dasel
asdf install dasel <version>
asdf global dasel <version>
Mise
Using mise.
List dasel versions available:
mise ls-remote dasel
Install a specific version (you can use the latest alias) and make it available globally:
mise install dasel@<version>
mise use -g dasel@<version>
Nix
To install using the Nix Package Manager (for non-NixOS)
nix-env -iA nixpkgs.dasel
Or NixOS:
nix-env -iA nixos.dasel
Windows
See manual install.
Manual
You can download a compiled executable from the latest release.
Note
Don’t forget to put the binary somewhere in your
PATH.
Linux (64 bit)
curl -sSLf "$(curl -sSLf https://api.github.com/repos/tomwright/dasel/releases/latest | grep browser_download_url | grep linux_amd64 | grep -v .gz | cut -d\" -f 4)" -L -o dasel && chmod +x dasel
mv ./dasel /usr/local/bin/dasel
Mac OS (64 bit)
curl -sSLf "$(curl -sSLf https://api.github.com/repos/tomwright/dasel/releases/latest | grep browser_download_url | grep -v .gz | grep darwin_amd64 | cut -d\" -f 4)" -L -o dasel && chmod +x dasel
mv ./dasel /usr/local/bin/dasel
Windows
$releases = curl -sSLf https://api.github.com/repos/tomwright/dasel/releases/latest
Invoke-WebRequest -Uri (($releases | ConvertFrom-Json).assets `
| Where-Object { $_.name -eq "dasel_windows_amd64.exe" } `
| Select-Object -ExpandProperty browser_download_url) `
-OutFile dasel.exe
Scoop
Use the scoop command-line installer to install dasel on windows 10.
scoop bucket add extras
scoop install dasel
Development Version
You can go install the cmd/dasel package to build and install dasel for you.
Note
You may need to prefix the command with
GO111MODULE=onin order for this to work.
go install github.com/tomwright/dasel/v3/cmd/dasel@master
Usage from Go
Introduction
The dasel CLI is a basic package that uses the dasel external API to query and modify data.
Your application can do the same.
External API
Note
Ensure you have imported the appropriate parsing packages. See parsing.
Dasel exposes a simple API that can be consumed by your go packages/modules.
There are three main funcs of interest:
Select- Query some data and receive the results in Go types.Query- Query some data and receive the results in Daselmodel.Valuetypes.model.Valueis more verbose to work with, but maintains ordering and retains metadata.- See the model package for implementation details.
Modify- Perform a query that will modify the given data in-place.
Read api.go for more details information.
Processing byte data
Dasel queries generally expect model.Value input data. These can be constructed manually by you, or you can use dasel parsers to read structured data from JSON, YAML, etc.
var inputBytes []byte // Your data
reader, _ := parsing.Format("json").NewReader(readerOptions)
inputData, _ := reader.Read()
Or you can use an in-memory value:
inputData := model.NewValue([]string{"foo", "bar", "baz"})
It’s worth noting that any data passed to the external API are converted to a model.Value internally using model.NewValue.
You can convert dasel values back to bytes with parsing.Format("json").NewWriter or back to a standard go data type with myValue.GoValue().
Parsing formats
Please note that you will have to import any dasel parser that you wish to use in your application. The Dasel CLI does this in cmd/dasel/main.go. E.g.
_ "github.com/tomwright/dasel/v3/parsing/csv"
_ "github.com/tomwright/dasel/v3/parsing/d"
_ "github.com/tomwright/dasel/v3/parsing/hcl"
_ "github.com/tomwright/dasel/v3/parsing/ini"
_ "github.com/tomwright/dasel/v3/parsing/json"
_ "github.com/tomwright/dasel/v3/parsing/toml"
_ "github.com/tomwright/dasel/v3/parsing/xml"
_ "github.com/tomwright/dasel/v3/parsing/yaml"
Dasel project structure
Dasel has the following main packages:
- dasel - The external API.
- model - A wrapper around reflection types. This is what Dasel uses to access and modify data internally.
- parsing - Parsing implementations for each of the supported languages (e.g.
JSON). Each subdirectory contains a read and writer implementation. - execution - The real code implementation of all dasel features.
- selector - Parse dasel queries and returns an AST which can be used by the
executionpackage.
Examples
Up to date examples are maintained within the GitHub repository under api_example_test.go.
Selecting basic data from an in-memory map
package main
import (
"context"
"fmt"
"github.com/tomwright/dasel/v3"
"github.com/tomwright/dasel/v3/execution"
)
func main() {
// Define the data that you want to query.
myData := map[string]any{
"users": []map[string]any{
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Tom", "age": 40},
},
}
// Define the query to run.
query := `users.filter(age > 27).map(name)...`
// Perform the dasel query.
selectResult, numResults, err := dasel.Select(
context.Background(),
myData,
query,
)
if err != nil {
panic(err)
}
fmt.Printf("Found %d results:\n", numResults)
// Select usually returns an array of type any, however this may change.
// You should validate the type assertion in real code.
selectResults := selectResult.([]any)
// Do something with the results.
for _, result := range selectResults {
fmt.Println(result)
}
// Output:
// Found 2 results:
// Alice
// Tom
}
Query syntax
Overview
Dasel queries are composed of one or more statements. Each statement describes how to navigate or transform the data, and the final statement determines the output value.
A statement is made up of a sequence of accessors or function calls, chained together with a dot (.) and terminated with a semi-colon (;).
- Accessors let you step into nested structures (e.g. objects, arrays, maps).
- Functions apply transformations or filters to the current value.
Example
Suppose you have the following JSON document:
{
"users": [
{
"id": 1,
"name": "Alice",
"active": true
},
{
"id": 2,
"name": "Bob",
"active": false
}
]
}
A dasel query might look like this:
$activeUsers = $root.users.filter(active == true);
$activeUsers.map(name)
$activeUsers =
Variable assignment.$root
Access the root document.users
Access theusersfield.filter(active == true)
Filter theuserslist to only include elements whereactiveistrue.;
Terminate the statement.$activeUsers
Access the active users variable we just created.map
Iterate through each active user, returning the specified value, in this casename.
&#xNAN;(Since this is the last statement, this is also the output value.)
Output:
[
"Alice"
]
This query could be written in a more compact form, or split into multiple statements for clarity.
The following examples are equivalent and will all produce the same result:
$root.users.filter(active == true).map(name)
$activeUsers = $root.users.filter(active == true);
$activeUsers.map(name)
$activeUsers = $root.users.filter(active == true);
$names = $activeUsers.map(name);
$names
Whitespace
Whitespace is no longer a factor when parsing selectors. The following examples will all do the same thing.
This is really expected, however since this wasn’t the case in previous versions I am specifically calling it out.
With whitespace
[
1,
2,
3
].map(
if ( $this >= 1 ) {
$this / 1
} else {
$this
}
)
Without whitespace
[1,2,3].map(if($this>=1){$this/1}else{$this})
Comments
You can add comments to your queries with the double forward slash //.
Everything from the start of a comment until the end of the line will be ignored by dasel.
Example
dasel -o json '
{ // Start of input object creation
"foo": "bar", // The base "foo" value.
"name": "Tom" // The original name
} // End of the input object
.
{ // Start of object re-creation
"baz": foo, // Rename foo to bar
name // Shorthand for "name": name
} // End of object re-creation'
{
"baz": "bar",
"name": "Tom"
}
Types/Literals
Integers
Integers are represented as whole numbers. E.g.
1,5234-
-530
Note: If -530 is detected as a bad binary expression (nothing subtract 530) it can be grouped, e.g. (-530).
Floats
Numbers are interpreted as floats when they contain a decimal place . or are followed with an f. E.g.
1.123.45123f
Booleans
Bools are matched by a case insentive match on true or false. E.g.
trueTrueTRUEfalseFalseFALSE
Strings
Strings are interpreted as a sequence of characters surrounded by quotes, both single and double. E.g.
"I am a string"'I am a string'"I am a string with an escaped \" inside of me"
Recursive Descent
The recursive descent operator (..) allows you to search deeply through the entire document tree, starting at the current node, and return all matching keys, indices, or values.
This operator is most commonly used to extract values from nested objects and arrays without knowing their exact path.
Syntax
..KEY
Return an array of all values of the given KEY, recursively.
..[INDEX]
Returns an array of the element at INDEX for every array found, recursively.
..*
Returns an array of all values (map values, array elements, scalars) at any depth.
Behaviour
..performs a depth-first traversal of the current node.- For objects/maps:
..KEYfinds all values where the key isKEY...*finds all values (for all keys).
- For arrays:
..[INDEX]selects the element atINDEXfrom every array found...*selects every element from every array found.
- Scalars (strings, numbers, booleans, nulls) are included when using
..*.
Examples
Example Input
{
"user": {
"name": "Alice",
"roles": ["admin", "editor"],
"meta": {
"active": true,
"score": 42
}
},
"tags": ["x", "y"],
"count": 10
}
1. Recursive Key Search
Get all values with the key name:
'..name'
Output:
["Alice"]
2. Recursive Array Index Search
Get the first element ([0]) of every array:
'..[0]'
Output:
["admin", "x"]
3. Recursive Wildcard (..*)
Get all values at any depth:
'..*'
Output:
[
"Alice",
"admin",
"editor",
true,
42,
"x",
"y",
10
]
Notes
..is shorthand for recursive search by key or index.- For more complex filtering (e.g. values where a key exists, or by type), use the
searchoperator. - The
..operator is widely known as the recursive descent operator, and is similar to://in XPath..in JSONPath and yq..in jq
Regex
Regex pattern are represented as unquoted strings, in the format of r/my regex pattern/.
Regex patterns can be used with the like =~ and not like !~ comparators.
Limitations
- Usage is limited to pattern matching for now. Value extraction will come in the future.
- Patterns must start with
r/and end with/.
Examples
Filter for strings starting with b
["foo", "bar", "baz"].filter($this =~ r/^b/)
[
"bar",
"baz"
]
String concatenation
To concatenate strings, simply use the + operator.
To concatenate non-string values into string values, use the toString function.
Examples
"hello" + " " + "world" // "hello world"
"i am " + toString(100) + " years old" // "i am 100 years old"
Arrays/slices
A slice/array is a sequence of elements. They are zero indexed, not a fixed size and can be modified on the fly.
Defining a new array
[1, 2, 3]
Appending elements to an array
[$someArray, 4]
Removing elements from an array
[1, 2, 3].filter($this % 2 == 0)
Accessing by index
$someArray[1]
Accessing last array index
$someArray[len($someArray)-1]
Accessing a range of items
The range index syntax can be a powerful tool: [start:end]
The result will be a new array containing the given range of indexes from start to end.
Take the first 5 items of an array
$someArray[0:4]
Take the last 5 items of an array
$someArray[ len($someArray)-6 : len($someArray)-1 ]
Objects/maps
An object/map is a set of key value properties.
Defining a new map
{"greeting": "hello"}
Creating a map using existing values
{"foo": "bar", "name": "Tom"}. // Just so you can see the input
{
"baz": foo,
name // Shorthand for "name": name
}
Adding new fields to a map
We can utilise the spread ... operator here.
Set "name" = "Tom" regardless of what is in the map already:
{
$this...,
"name": "Tom"
}
Set "name" = "Tom" only if it doesn’t already exist in the map:
{
"name": "Tom",
$this...
}
Conditionals
Conditionals allow you to select different values depending on an expression.
Dasel v3 supports both a long form if/else block and a compact ternary operator.
Long Form (if/else)
The long form is more explicit and easier to read for complex conditions.
if (<condition>) { <then-expression> } else { <else-expression> }
<condition>must evaluate to a boolean.<then-expression>is evaluated if the condition is true.<else-expression>is evaluated if the condition is false.
Example
Input JSON
{
"foo": {
"bar": "baz",
"bong": "selected",
"qux": "not-selected"
}
}
Query
$ dasel -i json -f input.json '.foo.if(bar == "baz") { bong } else { qux }'
Output
selected
Ternary Operator (? :)
Warning
Not yet implemented.
The ternary form is shorter and useful for inline conditions.
<condition> ? <then-expression> : <else-expression>
Example
Input JSON
{
"foo": {
"bar": "qux",
"bong": "selected",
"qux": "not-selected"
}
}
Query
$ dasel -i json -f input.json '.foo.(bar == "baz" ? bong : qux)'
Output
not-selected
Literals and Nesting
Both forms support literals and nested expressions.
Example 1: Literal results
Input JSON
{ "count": 7 }
Query
$ dasel -i json -f input.json 'if(count > 5) { "many" } else { "few" }'
Output
many
Example 2: Nested ternaries
Input JSON
{ "foo": { "bar": "zap", "bong": "BONG", "qux": "QUX", "zap": "ZAP", "default": "DEF" } }
Query
$ dasel -i json -f input.json '.foo.(bar == "baz" ? bong : (bar == "qux" ? qux : default))'
Output
DEF
Notes
- An
elsebranch is required.
Both theif/elseand ternary forms must specify anelseresult. - Both branches must return a value.
A conditional always evaluates to a result — you cannot have an empty branch. - Parentheses are recommended when nesting conditionals.
- Both branches must be valid dasel expressions (selectors, literals, or functions).
Spread
The spread operator ... can be used to spread the contents of a map or array across function arguments or array/object constructors, depending on the situation.
Anothor primary use-case is to output results as separate documents when put at the end of the output statement.
Examples
doSomething([1, 2, 3]...)
// equivalent to doSomething(1, 2, 3)
[[1, 2, 3]..., 4, 5, 6]
// resolves to [1, 2, 3, 4, 5, 6]
{ {"firstName": "Tom"}..., "lastName": "Wright" }
// resolves to { "firstName": "Tom", "lastName": "Wright" }
[1, 2, 3]...
// 1
// 2
// 3
Coalesce
The coalesce ?? operator can be used to provide default values when the given path does not exist, or causes some error.
The operator will pass through to the secondary value if:
- A given map key doesn’t exist
- A given array index doesn’t exist
- The given expressions returns
null - An operation is performed on an invalid type
Examples
Check if a property or index exists
if ($someArray[10] ?? false) {
// exists
} else {
// does not exist
}
if ($someMap.foo ?? false) {
// exists
} else {
// does not exist
}
Default values when something doesn’t exist
foo.bar.baz ?? "my sensible default"
Chaining
The coalesce operator can be chained, with items towards the left taking prescedence.
foo ?? bar ?? baz ?? false
Branches
Warning
This feature is potentially unstable. Must be used with the
--unstableflag.
Dasel includes the concept of branches. branch allows you to perform one or more sub queries, with each query output as a separate document.
This documentation is a little light, but will be improved with time.
Examples
Without branching
When we don’t branch, notice how the result is an array containing numbers.
$ cat numbers.json | dasel -i json 'numbers'
[
{
"x": 1
},
{
"x": 2
},
{
"x": 3
}
]
Branching on numbers
When we branch on the numbers, we actually get separate JSON documents out at the end.
$ cat numbers.json | dasel -i json 'branch(numbers...)'
{
"x": 1
}
{
"x": 2
}
{
"x": 3
}
Filtering on a branch
Since filter must be used on arrays and a branch isn’t technically an array, we can instead use ignore. This marks a specific branch as irrelevant and it will be stripped from the result.
[1,2,3].branch().if ( $this==2 ) { ignore() } else { $this }
2
3
Read/Write formats
Dasel supports a number of file formats out of the box.
| Format | Read | Write | Notes |
|---|---|---|---|
| json | :white_check_mark: | :white_check_mark: | |
| yaml | :white_check_mark: | :white_check_mark: | |
| hcl | :white_check_mark: | :white_check_mark: | Flags available. |
| csv | :white_check_mark: | :white_check_mark: |
Flags available. |
| toml | :grey_question: | :grey_question: |
Generally working. |
| xml | :white_check_mark: | :white_check_mark: | Flags available. |
| ini | :white_check_mark: | :white_check_mark: | Limited to basic sections + key values. |
| dasel | :white_check_mark: | :x: | This is not a real format, but instead allows dasel literals to be parsed on input strings. |
Stdin
It’s common that you will want to pass some input into dasel to work with.
The simplest way of doing so is sending it to stdin, e.g.
echo '{"message": "Hello world"}' | dasel -i json
This data could be in many formats (json, yaml, etc), so it’s important that you use -i, --input to specify the input file format.
Note that if you provide an input format, you must write to stdin other dasel will hang waiting for input.
Outputting the root document with –root
By default, dasel outputs the result of the final selector. This is useful when searching for data, but not so useful when performing modifications.
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json 'foo.bar'
"baz"
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json 'foo.bar = "bong"'
"bong"
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json --root 'foo.bar = "bong"'
{
"foo": {
"bar": "bong"
}
}
Stdout
Dasel writes to stdout.
You can modify the output with the -o, --out flag passing the required format, e.g. json, yaml etc.
$ echo '{"message": "Hello world"}' | dasel -i json -o yaml
message: Hello world
Getting the output you want
Dasel will output the result of the final expression by default, however in some cases it can be useful to output the input document, e.g.
Default behaviour
$ echo '{"user": {"name": "John"}}' |
dasel -i json 'user.name = {"first": user.name, "last": "Doe"}'
// outputs
{"first": "John", "last": "Doe"}
With –root
$ echo '{"user": {"name": "John"}}' |
dasel -i json --root 'user.name = {"first": user.name, "last": "Doe"}'
// outputs
{"user": {"name": {"first": "John", "last": "Doe"}}}
Modifying data
Tip
Use
--rootwhenever you are modifying data and intend to save it back to a file.
This ensures you get the complete updated document rather than just the changed value.
Output Behaviour
By default, dasel outputs the result of the final selector in your query.
This is convenient when you’re simply retrieving a value, but can be less helpful when you’re modifying data, since you often want to see the full document instead.
Retrieving a Value
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json 'foo.bar'
"baz"
Here, the final selector is foo.bar, so dasel outputs its value: "baz".
Modifying a Value
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json 'foo.bar = "bong"'
"bong"
When updating a value, dasel still outputs the result of the final selector — in this case, the new value "bong".
Outputting the Entire Document
To print the entire modified document, use the --root flag.
This changes the output to always return the full root node, regardless of the final selector.
$ echo '{
"foo": {
"bar": "baz"
}
}' | dasel -i json --root 'foo.bar = "bong"'
{
"foo": {
"bar": "bong"
}
}
Comparison
| Mode | Example Command | Output |
|---|---|---|
| Default | dasel -i json 'foo.bar = "bong"' | "bong" (final selector value) |
--root | dasel -i json --root 'foo.bar = "bong"' | Full document with updated "foo.bar" |
Variables
Dasel allows you to define variables for use in your other selectors.
Variables are referenced using a $ prefix.
Note that these variables are essentially globals, and once defined, they are accessible at any point in the execution.
Variables can be used alongside stdin.
From the environment
You can access environment variables using $ENV_VAR_NAME.
Note that changes to environment variables within dasel are not supported.
$ GREETING=hello NAME=tom dasel '$GREETING + " " + $NAME'
"hello tom"
From the CLI
You can set variables from the CLI by passing additional arguments in the form of:
--var name=format:content
If you wish to pass a file as a variable you can use:
--var name=format:file:filepath
$ echo 'message: Hello world' > test.yaml
$ dasel -o json testVar=yaml:file:test.yaml '$testVar.message'
"Hello world"
Note that at this time variables from the CLI are currently required to be documents read from the file system. There are plans to change this in the future.
Standard variables
Some variables are provided by dasel and will always exist:
$this- The current element$root- The root document passed throughstdin.
Read/Writer flags
Some parsers accept options that aren’t available in others, for this we use read/writer flags.
Format
--read-flag foo=bar
--write-flag foo=bar
Flags by parser
CSV
| Read/Write | Name | Values | Description |
|---|---|---|---|
| read/write | csv-delimiter | Any single character to use as a delimiter. E.g. ,, ; | Changes the delimiter used when reading/writing CSV files. |
XML
| Read/Write | Name | Values | Description |
|---|---|---|---|
| read | xml-mode | structured | Changes the internal structure that XML documents are read into. |
HCL
| Read/Write | Name | Values | Description |
|---|---|---|---|
| read | hcl-block-format | array | HCL block contents usually expand to an array when duplicate labels are defined on another block. Setting this to array will force blocks to always be an array of values, even when there are no duplicates. |
Editing files in place
With V3 the in-process file editing was removed so I can re-evaluate if it is actually needed and what it should look like.
In the meantime, the following is an example of how you can edit in-place.
dasel -i toml --root 'foo = "bar"' < file.toml > file.toml.tmp \
&& mv file.toml.tmp file.toml
- Read a file into dasel
< file.toml - Redirect the output to a tmp file
> file.toml.tmp - Move the tmp file over the original
mv file.toml.tmp file.toml
It is important to use the --root flag - this ensures dasel outputs the entire document.
Why do we need to go via a tmp file?
When you redirect output to a file bash will truncate that file before running the command.
This usually doesn’t cause an issue but will will in this case as the file is then empty when dasel tries to read it.
add
Adds all of the given numbers.
Accepts int and float.
- If any floats are given, float is returned.
- If no floats are given, int is returned.
Examples
add(1, 2, 3) // 5
[1, 2, 3].add($this...) // 5
len
Returns the length of the given value.
Accepts arrays, objects and strings.
Examples
len([0, 0, 0]) // 3
len({"foo": "bar", "hello": "world"}) // 2
len("hello") // 5
has
Returns true if the input data has the given key/index.
Expects a single argument of type string or int.
- If
string, returnstruewhen the input data is a map with a key matching the given value. - If
int, returnstruewhen the input data is an array and the given index is within range.
Examples
["foo", "bar", "baz"].has(1) // true
["foo", "bar", "baz"].has(3) // false
["foo", "bar", "baz"].has(-1) // false
["foo", "bar", "baz"].has("foo") // false
{"foo": "bar"}.has("foo") // true
{"foo": "bar"}.has("bar") // false
{"foo": "bar"}.has(0) // false
get
Returns data by key/index lookup.
Useful when looking up map keys containing a dot . , or when you want craft a dynamic key.
Expects a single argument of type string or int.
- If
string, performs a map lookup. - If
int, performs an array index lookup.
Examples
$ echo "['0.2.8']
key = 'value'" | dasel -i toml 'get("0.2.8")'
key = 'value'
min
Returns the smallest number in the given arguments.
Accepts int and float.
Examples
min(1, 2, 3) // 1
[1, 2, 3].min($this...) // 1
max
Returns the largest number in the given arguments.
Accepts int and float.
Examples
max(1, 2, 3) // 3
[1, 2, 3].max($this...) // 3
reverse
Reverses the input.
Examples
reverse("hello") // "olleh"
reverse([1,2,3]) // [3,2,1]
toString
Converts the given argument to a string.
Does not support maps or arrays at this time.
Examples
toString("hello") // "hello"
toString(123) // "123"
toString(123.4) // "123.4"
toString(false) // "false"
toInt
Converts the given argument to an int.
Does not support maps or arrays at this time.
Examples
toInt("1") // 1
toInt("1.2") // 1
toInt(123) // 123
toInt(123.4) // 123
toInt(false) // 0
toInt(true) // 1
toFloat
Converts the given argument to a float.
Does not support maps or arrays at this time.
Examples
toFloat("1") // 1
toFloat("1.2") // 1.2
toFloat(123) // 123
toFloat(123.4) // 123.4
toFloat(false) // 0
toFloat(true) // 1
typeOf
Returns the type of the given argument, as a string.
Examples
typeOf("") // "string"
typeOf([]) // "array"
typeOf(true) // "bool"
typeOf(null) // "null"
typeOf(1) // "int"
typeOf(1f) // "float"
typeOf(1.1) // "float"
map
The map function can be used to transform the contents of an array. It’s functions in a similar way to javascripts Array.prototype.map.
Examples
Simple addition
[1, 2, 3].map($this + 1)
// [2, 3, 4]
Extracting nested properties
[
{"x": "foo"},
{"x": "bar"},
{"x": "baz"}
].map(x)
// ["foo", "bar", "baz"]
Fizzbuzz
Given numbers.json
{
"numbers": [
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15
]
}
$ cat numbers.json | dasel -i json 'numbers.map(
if ($this % 3 == 0 && $this % 5 == 0) {
"fizzbuzz"
} elseif ($this % 5 == 0) {
"buzz"
} elseif ($this % 3 == 0) {
"fizz"
} else {
$this
}
)'
[
1,
2,
"fizz",
4,
"buzz",
"fizz",
7,
8,
"fizz",
"buzz",
11,
"fizz",
13,
14,
"fizzbuzz"
]
each
The each function is used to iterate through each item of an array. Comparable to a foreach loop.
The current item is accessible via the $this variable.
The response values from an each call is ignored. each is useful when you want to modify values in-place.
Most commonly used with:
- search
- recursive descent
--rootflag
Examples
Modifying data in-place
$ echo '[1,2,3]' | dasel -i json 'each($this = $this+1)'
[
2,
3,
4
]
filter
The filter function can be used to filter the contents of an array. It’s functions in a similar way to javascripts Array.prototype.filter.
Examples
[1, 2, 3].filter($this > 1)
// [2, 3]
join
The join function concatenates multiple values into a single string, inserting a delimiter between each value.
It is useful for turning arrays or multiple values into a delimited string (for example, CSV-style output).
Syntax
join(delimiter, values...)
or as a chained function:
<array>.join(delimiter)
Arguments
- delimiter (
string)
The string to insert between each value. - values (
string | array[string])
The values to join. These can be provided as:- Multiple arguments
- A single array
- A chained array input
Examples
Chained array input
["a","b","c"].join(",")
Output:
a,b,c
Variadic arguments
join(",", "a", "b", "c")
Output:
a,b,c
Array argument
join(",", ["a", "b", "c"])
Output:
a,b,c
Notes
- All arguments given to join are expected to be strings. Dasel will not try to convert for you.
- The order of values is preserved.
- This function is commonly used for formatting output for shells, logs, or downstream tools.
search
The search function performs a predicate-based recursive search of the document tree.
It allows you to find nodes that match specific conditions, not just by key name.
This makes search a more flexible and powerful alternative to the .. operator, which is shorthand for simple recursive key or index lookups.
Syntax
search(PREDICATE)
Where PREDICATE is a function that tests each node and returns true/false.
Behaviour
- Traverses the entire document tree, starting at the current node.
- Applies the given predicate to every node (objects, arrays, scalars).
- Returns all nodes that satisfy the predicate.
- Unlike
..,searchis not limited to key names or indices — it supports arbitrary conditions.
Predicates
Commonly used predicate functions include:
has("KEY")— true if the node has the given key.$this == VALUE— true if the node equalsVALUE.
📌 Check the functions documentation for a full list.
Examples
Example Input
{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
],
"meta": {
"active": true,
"score": 42
}
}
1. Search for Nodes with a Key
Find all nodes that contain a name field:
dasel -f data.json 'search(has("name"))'
Output:
{ "id": 1, "name": "Alice" }
{ "id": 2, "name": "Bob" }
2. Search for Specific Values
Find all nodes where the value equals 42:
dasel -f data.json 'search($this == 42)'
Output:
42
3. Combining Predicates
Find all nodes that have both id and name keys:
dasel -f data.json 'search(has("id") && has("name"))'
Output:
{ "id": 1, "name": "Alice" }
{ "id": 2, "name": "Bob" }
Comparison to ..
..is shorthand for recursive key/index lookups:..name≈search(has("name"))..[0]≈search(has(0))
searchallows arbitrary logic, making it more powerful but also more verbose.
Notes
searchis ideal when you need fine-grained control over what you’re looking for.- Use the recursive descent operator (
..) for simple lookups by key or index. - Both operators traverse the document tree recursively — the difference is specificity vs flexibility.
sortBy
Sorts the input array by the given expression, either ascending or descending.
Defaults to ascending.
Examples
Simple array
[1, 3, 5, 2, 4].sortBy() // [1, 2, 3, 4, 5]
[1, 3, 5, 2, 4].sortBy($this) // [1, 2, 3, 4, 5]
[1, 3, 5, 2, 4].sortBy($this, asc) // [1, 2, 3, 4, 5]
[1, 3, 5, 2, 4].sortBy($this, desc) // [5, 4, 3, 2, 1]
Sort by nested property
[
{"x": 1},
{"x": 3},
{"x": 5},
{"x": 2},
{"x": 4}
].sortBy(x)
// Results in
[
{"x": 1},
{"x": 2},
{"x": 3},
{"x": 4},
{"x": 5}
]
sum
Sums the given numeric inputs.
If any float is given, all inputs are converted to float and a float is returned.
Example
sum(1,2,3)
6
sum(1,2.2,3)
6.2
parse
parse allows you to convert strings to documents within your query.
Accepts 2 arguments:
- Format (
json,yaml,toml, etc) - String to parse
Example
parse("json", "{'name':'Tom'}").name
"Tom"
readFile
readFile allows you to read file contents at runtime and use the results in your selectors.
A common use-case may be to send the output into a parse call.
Accepts 1 arguments:
- Filepath
Example
Simple text
$greeting = readFile("greeting.txt");
$name = readFile("name.txt");
$greeting + " " + $name;
// "Hello Tom"
Parsing file contents
// Assuming names.json contains ["Tom", "Jim"]
$names = parse("json", readFile("names.json"));
len(names)
// 2
base64e
Base64 encodes the given string value.
Example
base64e("hello")
"aGVsbG8="
base64d
Base64 decodes the given string value.
Example
base64e("aGVsbG8=")
"hello"