Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

Note

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

Dasel mascot

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.

TagDescription
latestThe latest release version.
developmentThe 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=on in 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 Dasel model.Value types.
    • model.Value is 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 execution package.

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 the users field.
  • filter(active == true)
    Filter the users list to only include elements where active is true.
  • ;
    Terminate the statement.
  • $activeUsers
    Access the active users variable we just created.
  • map
    Iterate through each active user, returning the specified value, in this case name .
    &#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.1
  • 23.45
  • 123f

Booleans

Bools are matched by a case insentive match on true or false. E.g.

  • true
  • True
  • TRUE
  • false
  • False
  • FALSE

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:
    • ..KEY finds all values where the key is KEY.
    • ..* finds all values (for all keys).
  • For arrays:
    • ..[INDEX] selects the element at INDEX from 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
}

Get all values with the key name:

'..name'

Output:

["Alice"]

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 search operator.
  • 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

  1. Usage is limited to pattern matching for now. Value extraction will come in the future.
  2. 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 else branch is required.
    Both the if/else and ternary forms must specify an else result.
  • 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 --unstable flag.

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.

FormatReadWriteNotes
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.
All values read/written as strings.

toml:grey_question::grey_question:

Generally working.
Unsorted maps.

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 --root whenever 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

ModeExample CommandOutput
Defaultdasel -i json 'foo.bar = "bong"'"bong" (final selector value)
--rootdasel -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 through stdin.

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/WriteNameValuesDescription
read/writecsv-delimiterAny single character to use as a delimiter. E.g. ,, ;Changes the delimiter used when reading/writing CSV files.

XML

Read/WriteNameValuesDescription
readxml-modestructuredChanges the internal structure that XML documents are read into.

HCL

Read/WriteNameValuesDescription
readhcl-block-formatarrayHCL 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
  1. Read a file into dasel < file.toml
  2. Redirect the output to a tmp file > file.toml.tmp
  3. 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, returns true when the input data is a map with a key matching the given value.
  • If int, returns true when 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:

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 .., search is 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 equals VALUE .

📌 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:
    • ..namesearch(has("name"))
    • ..[0]search(has(0))
  • search allows arbitrary logic, making it more powerful but also more verbose.

Notes

  • search is 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:

  1. Format (json, yaml, toml, etc)
  2. 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:

  1. 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"