Nushell
Get Nu!
Getting Started
  • The Nushell Book
  • Command Reference
  • Cookbook
  • Language Reference Guide
  • Contributing Guide
Blog
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
  • 한국어
GitHub
Get Nu!
Getting Started
  • The Nushell Book
  • Command Reference
  • Cookbook
  • Language Reference Guide
  • Contributing Guide
Blog
  • English
  • 中文
  • Deutsch
  • Français
  • Español
  • 日本語
  • Português do Brasil
  • Русский язык
  • 한국어
GitHub

Nushell 0.115.0

Today, we're releasing version 0.115.0 of Nu. This release brings a major YAML rework, the new $ans REPL variable for inspecting your last result, Helix-style editing, and a lot of internal cleanup and fixes.

Where to get it

Nu 0.115.0 is available as pre-built binaries or from crates.io. If you have Rust installed you can install it using cargo install nu.

As part of this release, we also publish a set of optional plugins you can install and use with Nushell.

Table of contents

Highlights and themes of this release [toc]

YAML's Always More Labor [toc]

Thanks to @cptpiepmatz, Nushell's YAML support got a proper rebuild. We now use a stable, modern, maintained implementation that no longer tries to make YAML 1.1, the scary one, and YAML 1.2 behave like one big YAML-shaped compromise.

The two specs are now handled separately, from yaml defaults to YAML 1.2, tags work more deliberately, multi-document streams are supported, anchors and merge keys behave properly, and to yaml is clearer about values that cannot round-trip.

Take a look at all the examples here.

Ah, the $ans.last pipeline took so long to run [toc]

Ever had your last pipeline take forever, only to realize you forgot to assign the result to a variable? Worry no longer. Thanks to @fdncred, Nushell now has $ans, a Nushell-specific answer variable heavily inspired by calculators.

$ans keeps track of the last REPL result, including the output, duration, exit code, and the command you typed. Storing the output is opt-in: set $env.config.max_last_result_size to a filesize of your choosing, and $ans.last will keep up to that much of the previous pipeline result.

That means if your pipeline took 15 minutes and you do not want to run it again, you can finally breathe, do a quick let took_too_long = $ans.last, and you're golden. Take a closer look here.

Helix mode! [toc]

Alongside Vim mode, Nushell now has helix edit mode too. Set it with $env.config.edit_mode = helix, and that's it. You get a selection-first, Helix/Kakoune-style editing experience with normal, select, and insert modes.

Thanks to @kronberger-droid for the work here. More details are here.

Lots of internal wrangling [toc]

This release does not have a huge pile of public user-facing additions, but there was a lot of work inside Nushell. Be in awe of the long list of things happening in the ✨ Hall of Fame ✨, and also check out the long list of fixes.

As always, a big shoutout to everyone contributing and making Nushell better. The internals may not always get the flashiest highlight section, but they are doing a lot of heavy lifting this time.

Changes [toc]

Breaking changes [toc]

YAML got a proper rework [toc]

PR #18487 by @cptpiepmatz

YAML has been a problem child for quite some time now. This release replaces the old serde_yaml-based implementation with a new one built on serde-saphyr and granit-parser. With that we now get clearer YAML behavior, better round-tripping, proper tag support, multi-document streams, anchors, aliases, merge keys, and a few new options for configuring how the output should look like.

Breaking changes

The big breaking change is that Nu no longer tries to parse YAML as an awkward mix of YAML 1.1 and YAML 1.2. We now default to YAML 1.2, which is usually the the less crazy choice. If your files or scripts relied on old YAML 1.1 scalar magic, pass --spec 1.1.

use std/assert

# Default YAML 1.2 behavior: these stay strings.
assert equal ("yes" | from yaml) "yes"
assert equal ("off" | from yaml --spec 1.2) "off"

# YAML 1.1 keeps the classic YAML oddities.
assert equal ("yes" | from yaml --spec 1.1) true
assert equal ("off" | from yaml --spec 1.1) false

This specifically breaks octal numbers. In the 1.1 spec, a value is interpreted as an octal number if it starts with the 0 digit. It is then parsed as an octal value. If the value is not valid octal, it is instead returned as a string.

The 1.2 spec made this much more sensible by allowing leading zeros on regular numbers and requiring octal numbers to use the 0o prefix.

use std/assert

# YAML 1.1 uses a leading zero as an octal indicator.
assert equal ("0247" | from yaml --spec 1.1) 0o247
assert equal ("0o247" | from yaml --spec 1.1) "0o247"

# YAML 1.2 replaced that with the `0o` prefix.
assert equal ("0247" | from yaml --spec 1.2) 0247
assert equal ("0o247" | from yaml --spec 1.2) 0o247

Did you know that YAML 1.1 supports sexagesimal values like 190:20:30? No, well in the 1.1 spec these as base-60 numbers that can be used to represent time but noone knows that, so 1.2 got rid of them. And as Nushell now defaults to 1.2 we interpret these as strings.

use std/assert

assert equal ("190:20:30" | from yaml) "190:20:30"
assert equal ("190:20:30" | from yaml --spec 1.1) 685230

assert equal ("02472256" | from yaml) 2472256
assert equal ("02472256" | from yaml --spec 1.1) 685230

from yaml is stricter about mapping keys now, too. Nushell record keys are strings, so plain YAML keys that resolve to booleans, numbers, or null are rejected by default. If you want the old loose behavior, use --key-resolution verbatim and Nushell will keep the original key text.

'true: enabled' | from yaml
# Error: YAML key resolves to a boolean, but Nushell record keys are strings

'true: enabled' | from yaml --key-resolution verbatim
# => {true: enabled}

Tags also mean tags now. Previously, tagged scalars weren't really handled properly, often they were just ignored and handled as plain strings but in YAML they describe the data, usually as some types. Now unknown tags error by default but you can use --ignore-tags to just ignore the tags and deal with them yourself.

'Key: !Sub ${AWS::StackName}' | from yaml
# Error: unknown YAML tag

'Key: !Sub ${AWS::StackName}' | from yaml --ignore-tags
# => {Key: "${AWS::StackName}"}

to yaml is also more specific about values that cannot round-trip. By default it errors instead of quietly turning them into something else. If that is unwatned, choose the behavior explicitly with --non-roundtrip null or --non-roundtrip lossy. The --serialize flag is still available but will probably be deprecated in the future.

{|| $in } | to yaml
# Error: closures are not round-trippable through YAML

{|| $in } | to yaml --non-roundtrip null
# => null

{|| $in } | to yaml --serialize
# => !closure "{|| $in }"

One more relevant breaking change: generated YAML may not look exactly like it did before. The new serializer quotes strings more carefully, writes tags for Nushell-specific values, and lets you configure indentation. If you depended on a specific YAML output, you might need to check that.

Tags and round-tripping

Nushell now understands standard YAML tags like !!timestamp,!!binary, !!omap, !!pairs, and !!set. It also writes Nushell-specific local tags for values that YAML did not define globally, such as filesizes, durations, ranges, globs, and cell paths.

name: Cargo.toml
size: !filesize 17515
modified: !!timestamp 2026-08-14T23:30:19.144306+02:00
path: !cell-path $.items.0.name

Here, !filesize and !cell-path are Nushell tags, while !!timestamp is a standard YAML tag. When you read this back with from yaml, those fields come back as proper typed values instead of plain strings or integers.

If you want the YAML version and Nushell tag prefix written out explicitly, use to yaml --add-directives or to yaml -d.

ls | where name == Cargo.toml | first | to yaml --add-directives
%YAML 1.2
%TAG ! tag:nushell.sh,2026:
---
name: Cargo.toml
type: file
size: !filesize 17515
modified: !!timestamp 2026-08-14T23:30:19.144306+02:00

Multiple documents

YAML streams with more than one document work properly now. By default, from yaml returns a single document directly, but returns a list if the stream has multiple documents. If you want to be explicit, use --multiple list to always get a list or --multiple single to reject multi-document input.

name: dev
---
name: prod
> $yaml | from yaml
╭───┬──────╮
│ # │ name │
├───┼──────┤
│ 0 │ dev  │
│ 1 │ prod │
╰───┴──────╯
> 'name: dev' | from yaml --multiple list
╭───┬──────╮
│ # │ name │
├───┼──────┤
│ 0 │ dev  │
╰───┴──────╯
> $yaml | from yaml --multiple single
Error: shell::yaml::parse::too_many_documents

  × Too many documents
   ╭─[repl_entry #8:1:9]
 1 │ $yaml | from yaml --multiple single
   ·         ────┬────
   ·             ╰── Found more than one document, but requested only one
   ╰────
  help: Try without `--multiple single`

This also works the other way round. to yaml --multiple writes each item in a list as its own YAML document.

[{name: dev}, {name: prod}] | to yaml --multiple
name: dev
---
name: prod

Anchors, aliases, and merge keys

Anchors and aliases are handled more completely now, including merge keys. Previously this just did not work at all.

defaults: &defaults
  timeout: 30
  retries: 3

production:
  <<: *defaults
  timeout: 60
> $yaml | from yaml | get production
╭─────────┬────╮
│ timeout │ 60 │
│ retries │ 3  │
╰─────────┴────╯

Useful flags

On the parsing side, the main new flags are from yaml --spec 1.1|1.2, --multiple auto|list|single, --ignore-tags, and --key-resolution strict|verbatim.

On the writing side, the handy flags are --spec, --add-directives/-d, --multiple/-m, --indent/-i, --compact-list-indent, --quote/-q, --non-roundtrip, and --serialize/-s.

For example, --quote and --indent can help when another tool expects a particular style.

{outer: {inner: value}} | to yaml --indent 4 --quote double
outer:
  inner: 'value'

Disallowed shadowing parser keywords [toc]

PR #18662 by @fdncred

Trying to shadow a keyword will produce an error now.

> def def [] {}
Error: nu::parser::name_is_keyword

  × Can't use parser keyword `def` as command name.
   ╭─[repl_entry #9:1:5]
 1 │ def def [] {}
   ·     ─┬─
   ·      ╰── 'def' is a parser keyword
   ╰────
  help: Parser keywords cannot be shadowed (including via module exports and `use *`). Choose a different command name
        so language constructs keep working.

The nu binary no longer ships with --testbin [toc]

PR #18719 by @cptpiepmatz

The nu binary used to include a handful of test binaries for our integration tests. These were available through nu --testbin. To reduce the size and complexity of the binary, this option is no longer available. Everything the test binaries could do can also be done with Nushell itself.

If your scripts depended on these test binaries, use an equivalent Nushell command or call nu -n -c "some commands" with the same behavior.

Other breaking changes [toc]

  • Removed the idx import and idx export commands, which had very little use case, as the search backend (FFF) is not designed for persistent disk caching. idx init is now the one way to build the in-memory index; watching remains enabled by default and can be disabled with --no-watch. (#18679)

Additions [toc]

drop now supports binary inputs, and chunks, first, last, take, skip and drop support filesize arguments [toc]

PR #18511 by @Tyarel8

These commands can work on binary data, it only makes sense for them to work with not just int but filesize arguments as well:

# split compressed file into 10MiB chunks
open --raw file.7z
    | chunks 10MiB
    | enumerate
    | each {|chunk|
        let suffix = $chunk.index + 1 | fill -a right -c '0' -w 3
        $chunk.item
        | save $"file.7z.($suffix)"
    }

Added constant expressions in match arms [toc]

PR #18559 by @fdncred

The match command can now evaluate constants in match arms like this:

> match "test" {
  ('t' + 'es' + 't') => { print 'OK' }
}
OK

or a more real-world case:

> const MY_DIR_CONST = 'D:\Projects\nushell'
> let path = pwd
> $path
D:\Projects\nushell\crates\nu-command
> match $path {
  ($MY_DIR_CONST + '\sub-dir1') => { print "sub-dir" }
  ($MY_DIR_CONST + '\crates\nu-command') => { print "nu-command" }
}
nu-command

Added external_arg annotations for script parameters [toc]

PR #18512 by @skyrocket1643

You can now do the following:

script.nu
def main [
   a: external_arg
   b: external_arg
   -c: external_arg
   ...rest: external_arg
] {
   [
      [label value type];
      [a $a ($a | describe)]
      [b $b ($b | describe)]
      [c $c ($c | describe)]
      [rest $rest ($rest | describe)]
   ]
}

Then:

> nu ./script.nu 0001 true -c true -- 001 true
╭───┬───────┬──────────────┬────────────╮
│ # │ label │    value     │    type    │
├───┼───────┼──────────────┼────────────┤
│ 0 │ a     │ 0001         │ glob       │
│ 1 │ b     │ true         │ glob       │
│ 2 │ c     │ true         │ glob       │
│ 3 │ rest  │ ╭───┬──────╮ │ list<glob> │
│   │       │ │ 0 │ 001  │ │            │
│   │       │ │ 1 │ true │ │            │
│   │       │ ╰───┴──────╯ │            │
╰───┴───────┴──────────────┴────────────╯

any and all now accept row conditions just like where [toc]

PR #18353 by @Mrfiregem

In addition to the current closure syntax, any and all can now be given row conditions to make writing filters more streamlined.

[9 8 7 6] | enumerate | any item == index * 2

Just like with where, you can reference column names directly, and use the $it variable to construct predicates given to both commands, or continue to use closures for more extensive constructions.

[1sec 1min 1hr] | all ($it | describe) == 'duration'

Added matrix custom value and 21 subcommands [toc]

PR #18553 by @fdncred

A new matrix custom value type enables high-performance matrix math in Nushell, backed by the ndarray library for Rust.

Constructors:

  • matrix zeros <dims> — create a matrix filled with zeros
  • matrix identity <n> — create an n×n identity matrix
  • into matrix — convert a table/list-of-lists/list-of-records into a matrix

Access:

  • matrix get-row <index> — extract a row as a list
  • matrix get-col <index> — extract a column as a list (2D only)
  • matrix set-row <index> <values> — replace a row
  • matrix set-col <index> <values> — replace a column (2D only)

Arithmetic:

  • matrix add <matrix|scalar> — element-wise addition with optional --broadcast
  • matrix subtract <matrix|scalar> — element-wise subtraction with optional --broadcast
  • matrix scale <scalar> — multiply all elements by a scalar
  • Matrix values also support <operator> expressions: $m + $n, $m * 2.0, $m == $n

Linear algebra:

  • matrix multiply <matrix> — dot product (supports 1D×1D, 2D×1D, 1D×2D, 2D×2D)
  • matrix transpose — swap rows and columns (nD reverses all axes)

Transforms:

  • matrix reshape <dims> — change dimensions
  • matrix reshape --flatten — flatten to 1D

Element-wise: (could rename this to matrix each if map is confusing)

  • matrix map { |e| ... } — apply a closure to each element, returning a new matrix

Reductions:

  • matrix sum / matrix sum --axis <n> — sum all or along an axis
  • matrix mean — arithmetic mean of all elements
  • matrix max / matrix max --axis <n> — maximum all or along an axis
  • matrix reduce --fold <init> { |acc e| ... } — fold all elements to a single value

Output:

  • matrix into-nu — convert to table (list of lists)
  • matrix into-nu --as-records — convert to table of records with auto-generated column names

Examples

> # Create and manipulate matrices
> [[1 2 3] [4 5 6]] | into matrix | matrix transpose | matrix into-nu | to nuon
[[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]]
> matrix identity 3 | matrix scale 5 | matrix into-nu | to nuon
[[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]]

> # Matrix multiplication
> [[1 2] [3 4]] | into matrix | matrix multiply ([[1 0] [0 1]] | into matrix) | matrix into-nu | to nuon
[[1.0, 2.0], [3.0, 4.0]]

> # Element-wise operations
> [[1 2] [3 4]] | into matrix | matrix map { |e| $e * 2 } | matrix sum
20.0

> # Broadcasting
> matrix zeros 2 3 | matrix add --broadcast ([[1.0 2.0 3.0]] | into matrix) | matrix into-nu | to nuon
[[1.0, 2.0, 3.0], [1.0, 2.0, 3.0]]

> # Row/column access
> matrix identity 2 | matrix get-row 1 | to nuon
[0.0, 1.0]

> # Shape metadata via cell path
> matrix identity 2 | $in.shape
╭───┬───╮
│ 0 │ 2 │
│ 1 │ 2 │
╰───┴───╯
> matrix identity 2 | $in.ndim
2
> matrix identity 2 | $in.size
4

Standard iterator commands redirect to matrix-specific ones

  • each on a matrix → errors: "Use matrix map for element-wise operations"
  • par-each on a matrix → errors: "Use matrix map for element-wise operations"
  • reduce on a matrix → errors: "Use matrix reduce --fold <initial> { ... }"

Added std-rfc date floor and date ceil commands [toc]

PR #18640 by @Bahex

Added two new std-rfc commands, date floor and date ceil for rounding datetime values down and up, respectively, to specified duration boundaries.

> use std-rfc/date *

> # Round down to the nearest hour
> 2026-07-15T12:11:10-04:00 | date floor 1hr
Wed, 15 Jul 2026 12:00:00 -0400 (a month ago)
> 1969-12-31T23:30:00+00:00 | date floor 1hr
Wed, 31 Dec 1969 23:00:00 +0000 (56 years ago)

> # Round date up to nearest hour
> 2026-07-15T12:11:10-04:00 | date ceil 1hr
Wed, 15 Jul 2026 13:00:00 -0400 (a month ago)
> 1969-12-31T23:30:00+00:00 | date ceil 1hr
Thu, 1 Jan 1970 00:00:00 +0000 (56 years ago)

Added idx watch for streaming indexed filesystem changes [toc]

PR #18639 by @fdncred

Added idx watch to stream filesystem change events from a live idx index as tabular records (kind, path). Requires idx init with watching enabled. Optional pattern, --ignore, --timeout, and --max-events are supported for filtering and clean stream termination. Events respect gitignore/index ignores and can be piped into normal Nushell pipelines.

Also updated the fff-search dependency to 0.10.0 (enables the watch subscription API).

Examples:

idx init . --wait
idx watch
idx watch "**/*.rs" --ignore [target]
idx watch | where kind == "modified" | each {|e| print $"changed: ($e.path)"}
idx watch --max-events 1 --timeout 5sec

Added comparison operators for semver values [toc]

PR #18706 by @fdncred

semver values can now be compared with ==, !=, <, <=, >, and >=, using normal semantic version ordering:

> ('2.0.1' | into semver) > ('1.9.9' | into semver)
true

> ('2.0.1' | into semver) < ('1.9.9' | into semver)
false

> ('1.2.3' | into semver) == ('1.2.3' | into semver)
true

> ('1.0.0-alpha' | into semver) < ('1.0.0' | into semver)
true

A version string on the right-hand side is also accepted when it is a valid semver:

> ('2.0.1' | into semver) > '1.9.9'
true

Added --include to take while and take until [toc]

PR #18623 by @Bahex

take until and take while commands get a new --include (-i) flag, which allows you to take extra items after the stream would have otherwise stopped:

> date now
| into record
| transpose key val
| take until { $in.key == day } --include 1
╭───┬───────┬──────╮
│ # │  key  │ val  │
├───┼───────┼──────┤
│ 0 │ year  │ 2026 │
│ 1 │ month │    8 │
│ 2 │ day   │   15 │
╰───┴───────┴──────╯

Improved completion caching, dispatch, and reliability [toc]

PR #18761 by @philocalyst

  • Added $env.config.completions.cache_size (default: 100) to control that cap.
  • Completion results now persist across prompts instead of being discarded on every new prompt,.
  • Fixed a potential panic when narrowing file/directory completions on a path containing multi-byte (non-ASCII) characters.
  • commandline complete --type now validates its --type argument and no longer panics on an out-of-range cursor.
  • use, overlay use, export use, source-env, hide-env, attr complete, and which now go through the same completion dispatch as other builtins, fixing inconsistent/missing completions in a few of them

Added commandline set-prompt for async prompt updates [toc]

PR #18660 by @philocalyst

Added the commandline set-prompt command for ad-hoc updates to a rendered prompt.

Examples:

Stand-in values, with background job spawn:

$env.PROMPT_COMMAND = { $"(ansi green)~(ansi reset)> " }

$env.PROMPT_COMMAND_RIGHT = {
    job spawn {
        let branch = (git branch --show-current | complete | get stdout | str trim)
        commandline set-prompt --right $"(ansi yellow)($branch)(ansi reset)"
    }

    ""  # show nothing on the right until the background job fills it in
}
# Replace the left prompt with a freshly rendered string.
job spawn { sleep 1sec; commandline set-prompt $"(ansi green)me> (ansi reset)" }

# Replace the right prompt.
job spawn { sleep 1sec; commandline set-prompt --right $"right (date now | format date '%H:%M:%S')" }

# Replace the default/emacs indicator.
job spawn { sleep 1sec; commandline set-prompt --indicator $" (char prompt)" }

# Replace the vi insert and normal mode indicators independently.
job spawn { sleep 1sec; commandline set-prompt --vi-insert ": " --vi-normal "n " }

# Replace the multiline continuation indicator.
job spawn { sleep 1sec; commandline set-prompt --multiline "... " }

# Replace multiple prompt segments in one call.
job spawn { sleep 1sec; commandline set-prompt --right "67" --indicator "69" }

# Stream a slow prompt segment in from a background job.
job spawn { sleep 1sec; commandline set-prompt $"(git branch --show-current) > " }

Added $ans for accessing the last REPL result [toc]

PR #18729 by @fdncred

PR #18827 by @fdncred

PR #18836 by @fdncred

$ans now stores information about the last successful Nushell result as a record, including its output, duration, and exit code. Like $in, $nu, and $env, $ans is now a reserved variable name, so scripts that use let ans = ... will need to be updated.

The amount of memory used to store the last output can be controlled with $env.config.max_last_result_size. It accepts a filesize and defaults to 0b, which disables storing the output in $ans.last and makes that part of the feature opt-in. The rest of the $ans record remains available.

To enable $ans.last, set $env.config.max_last_result_size to a reasonable value such as 1Mb. If the configured limit is reached, the stored output is truncated and a warning is shown when you access it.

> $env.config.max_last_result_size = 10mb
> ls | first 2
╭───┬────────────────┬──────┬───────┬──────────────╮
│ # │      name      │ type │ size  │   modified   │
├───┼────────────────┼──────┼───────┼──────────────┤
│ 0 │ .cargo         │ dir  │   0 B │ 2 weeks ago  │
│ 1 │ .gitattributes │ file │ 113 B │ 2 months ago │
╰───┴────────────────┴──────┴───────┴──────────────╯
> $ans
╭───────────┬──────────────────────────────────────────────────────╮
│           │ ╭───┬────────────────┬──────┬───────┬──────────────╮ │
│ last      │ │ # │      name      │ type │ size  │   modified   │ │
│           │ ├───┼────────────────┼──────┼───────┼──────────────┤ │
│           │ │ 0 │ .cargo         │ dir  │   0 B │ 2 weeks ago  │ │
│           │ │ 1 │ .gitattributes │ file │ 113 B │ 2 months ago │ │
│           │ ╰───┴────────────────┴──────┴───────┴──────────────╯ │
│ exit_code │ 0                                                    │
│ duration  │ 14ms 474µs 800ns                                     │
│ command   │ ls | first 2                                         │
╰───────────┴──────────────────────────────────────────────────────╯
$ans.last          # previous pipeline value
$ans.exit_code     # int (same idea as $env.LAST_EXIT_CODE)
$ans.duration      # duration value (from the same timing as $env.CMD_DURATION_MS)
$ans.command       # the last input as a raw string

Added Helix edit mode [toc]

PR #18830 by @kronberger-droid

Use $env.config.edit_mode = helix to enable a selection-first, Helix/Kakoune-style edit mode with normal, select, and insert modes. Motions extend or move the selection, while verbs act on it.

Menu keybindings such as Tab, Ctrl-r, and F1 work as they do in the other edit modes. Custom keybindings can target helix_normal, helix_insert, and helix_select, and cursor shapes can be configured with cursor_shape.helix_*.

Helix edit mode is included by default through the helix Cargo feature. To build without it, disable the default features with --no-default-features.

Added configurable visual selection styling [toc]

PR #18838 by @kronberger-droid

Added color_config.selection and color_config.selection_cursor to style the line editor's visual selection and the cursor cell inside it:

$env.config.color_config.selection = { attr: r }         # default
$env.config.color_config.selection_cursor = { attr: n }  # default

With the defaults a block cursor looks as before; underscore and line cursor shapes are now visible inside selections.

Added KDL v1/v2 support and JSON-in-KDL output [toc]

PR #18779 by @fdncred

from kdl and to kdl now support KDL language versions with --spec 1 or --spec 2 (default 2). Parsing is strict: v1 keyword style (true/false/null) and v2 style (#true/#false/#null) are not mixed unless you convert with an explicit emit spec.

> {a: 1, b: true} | to kdl --spec 1
- a=1 b=true

> {a: 1, b: true} | to kdl --spec 2
- a=1 b=#true

> "item 1 enabled=true" | from kdl --spec 1 | to kdl
item 1 enabled=true

Nu type annotations (YAML-tag analogue)

> # Promote (filesize) on from
> 'node (filesize)1024' | from kdl | get 0.args.0
1,0 kB

> # Emit annotated Nu types
> {size: 1kb} | to kdl
- size=(filesize)1000

Dual data models: nodes and JSON-in-KDL

  • from kdl defaults to --format nodes: a list of node rows (name, args, props, children) suitable for real config documents.
  • to kdl defaults to --format jik: JSON-in-KDL with a single top-level - node, so records and lists serialize predictably.
> {a: 1, b: true} | to kdl
- a=1 b=#true

> [1 2 3] | to kdl
- 1 2 3

> 'node one; node two' | from kdl | to kdl
node one
node two

This replaces the previous to kdl heuristic that flattened values under synthetic node names such as root.

Added deprecation metadata to scope commands [toc]

PR #18815 by @Mrfiregem

You can now programmatically access information about deprecated flags and commands using scope commands.

> scope commands | where name == "str downcase" | first | get deprecation_info.0
╭───────────────────────────┬─────────────────────────────────────────────────────────────────────────────────╮
│ type                      │ Command                                                                         │
│ label                     │ str downcase was deprecated in 0.114.0 and will be removed in a future release. │
│ flag                      │                                                                                 │
│ since                     │ 0.114.0                                                                         │
│ expected_removal          │                                                                                 │
│ help                      │ Use `str lowercase` instead.                                                    │
╰───────────────────────────┴─────────────────────────────────────────────────────────────────────────────────╯

Added loose semver parsing and semver table coloring [toc]

PR #18819 by @fdncred

Semantic version values are now displayed in cyan_bold in tables, making them easier to distinguish from other data types. into semver and into semver-range also now support a --loose option for parsing versions with common v-style prefixes, including v1.2.3, v.1.2.3, v:1.2.3, v-1.2.3, and v_1.2.3.

Other additions [toc]

  • Added support for passing lists into into semver, and for providing cell paths to do things like $nu.os-info | into semver kernel_version or ["1.2.0", "0.3.12"] | into semver. (#18567)
  • polars rolling can now be used natively with lazy frames and be used in expressions. (#18730)
  • Add support for additional arguments to nu -c/nu --commands with -- (#18576)
  • Added completions to format duration's and format filesize's unit argument. (#18783)
  • In helix edit mode, keybindings with mode: helix_select now target select mode's own keybinding table instead of being shared with helix_normal. (#18833)
  • Added to txt alongside to text, following the existing to yaml / to yml pattern. (#18735)
  • into binary now accepts duration input (e.g. 1sec, 1hr, …). (#18522)

Performance [toc]

Faster large binary value processing [toc]

PR #18572 by @Alb-O

Large binary values are now substantially cheaper to clone, stream, slice, and convert.

Commands that repeatedly process large binary values now avoid copying the entire value at each step, with repeated slicing and integer conversion roughly 3.4x faster.

Faster large list and table access [toc]

PR #18636 by @Alb-O

Large lists and tables are now much faster to read from, load from variables, and capture in closures.

Accessing a small part of a large list, such as $list.0, no longer copies the entire list each time the variable is loaded. In a 100,000-element test, 200 repeated reads improved from roughly 131 ms to 138 µs (~950x faster).

Other performance improvements [toc]

  • Improved performance of str replace --regex and str replace --multiline when working with lists, tables, and records with many string values, roughly a 10x speed boost. (#18508)
  • lines command with string value (non-stream) input no longer eagerly creates a list. Instead it returns a list stream, producing items lazily just like it does with text/byte stream inputs. (#18753)
  • Using built-in commands with --regex parameters should be faster in tight loops now because they are able to use the LRU cache for regex. (#18797)

Other changes [toc]

  • It is now not allowed to have export main in a module that is named to shadow an keyword. This shows and error now. (#18619)
  • The default left and right prompts no longer include ansi color escapes if the user has disabled color. (#18506)
  • Improved hash md5 and hash sha256 help to show that both commands support list<string> and list<binary> inputs. (#18638)

Bug fixes [toc]

Fixed nested try/finally blocks interfering with outer error handling [toc]

PR #18519 by @aionescu

When nesting a try/finally block within a try or try/catch block, it no longer prevents the outer block from catching errors.

This is showcased by the following code:

# try-inner.nu
try {
    try { print "inner" } finally { print "finally" }
    error make { msg: "error" }
}
print "outer"

Output before this change:

> run try-inner.nu
inner
finally
Error: nu::shell::error

  × error
   ╭─[D:\Projects\nushell\scratch\try-inner.nu:3:14]
 2 │   try { print "inner" } finally { print "finally" }
 3 │   error make { msg: "error" }
   ·              ────────────────
 4 │ }
   ╰────

Note that the error was surfaced despite being thrown inside a try block!

Output after this change:

> run scratch/try-inner.nu
inner
finally
outer

Fixed negative arguments for oneof parameters [toc]

PR #18514 by @Tyarel8

Parameters with int, float and number types can be supplied negative arguments:

> def foo [p: int] { $p }
> foo -2
-2

However this didn't work with parameters with types like oneof<int, ...>:

> def foo [p: oneof<int, string>] { $p }
> foo -2
Error: nu::parser::unknown_flag

  × The `foo` command doesn't have flag `-2`.
   ╭─[repl_entry #9:1:6]
 1 │ foo -2
   ·      ┬
   ·      ╰── unknown flag
   ╰────
  help: Use `--help` to see available flags

This is now fixed:

> def foo [p: oneof<int, string>] { $p }
> foo -2
-2

Fixed ps -l failing when processes exit during collection [toc]

PR #18542 by @rabindra789

Fixed a Linux race condition where ps -l could fail if a process exited while process information was being collected.

The exited process is now skipped instead of causing the command to fail.

Example

Before:

Error getting process stat
File not found: /proc/<pid>/stat

After:

ps -l continues running and omits the exited process.

Fix panic and infinite loop in seq on overflow and zero increment [toc]

PR #18596 by @santhreal

seq now handles zero increments and integer overflow safely. Using seq <first> 0 <last> returns an increment cannot be 0 error instead of looping indefinitely or producing no output. Sequences that reach the i64 boundary also terminate cleanly rather than panicking or wrapping around.

Fixed recursive glob behavior in the experimental dc-glob backend [toc]

PR #18704 by @fdncred

With --experimental-options=[dc-glob] enabled, recursive glob patterns now behave more consistently. A bare ** expands to directories at any depth, including the current directory, while **/* lists files and directories below the starting path without including the starting directory itself. Prefixed patterns such as foo/** similarly include the prefix directory and its nested directories, but not regular files.

Patterns with additional path segments, such as **/*/* and **/*/*/*, now once again enforce their expected minimum depth instead of ignoring the extra /* segments. This behavior differs slightly from the legacy nu-glob backend, but matches the common behavior of the glob crate.

Examples

# enable dc-glob for the session
NU_EXPERIMENTAL_OPTIONS=dc-glob nu
# or: nu --experimental-options=[dc-glob]

mkdir 0/1/2/3
touch 0/1/2/3/file.txt
cd 0

glob '**'
# start dir + nested directories only (no file.txt)

glob '**/*'
# everything under start ÔÇö not the start dir itself

glob '**/*/*'
# paths at least 2 components deep

glob '**/*/*/*'
# paths at least 3 components deep (e.g. 1/2/3 and 1/2/3/file.txt)

mkdir foo/bar
touch foo/sibling.txt
glob 'foo/**'
# foo and foo/bar only (not sibling.txt)

Matcher-level checks (debug flags require dc-glob):

glob --dbg-matches '**/*/*' '1'       # false
glob --dbg-matches '**/*/*' '1/2'     # true
glob --dbg-matches '**/*/*/*' '1/2'   # false
glob --dbg-matches '**/*/*/*' '1/2/3' # true
glob --dbg-matches '**/foo' 'foo'     # true
glob --dbg-matches 'foo/**' 'foo'     # true
glob --dbg-matches 'foo/**' 'foo/bar' # true
glob --dbg-matches 'foo/**' 'foobar'  # false
glob --dbg-matches '*/*' '1'          # false

Fixed inconsistent group-by handling of null keys [toc]

PR #18709 by @fdncred

group-by no longer maps null to the empty string, and treats null the same for list values, cell paths, and closures.

Before (inconsistent)
> # list: null became "" → 2 groups
> [ a null ] | group-by | values | length
2

> # cell path: null dropped → 1 group
> [ { x: a } { x: null } ] | group-by x | values | length
1

> # closure: null became "" → 2 groups
> [ { x: a } { x: null } ] | group-by { get x } | values | length
2

> # null and "" collapsed into one group
> [ a "" null ] | group-by | to nuon --raw
{a:[a],"":["",null]}
After (consistent)
> # All three return 1 (null omitted from record output)
> [ a null ] | group-by | values | length
1
> [ { x: a } { x: null } ] | group-by x | values | length
1
> [ { x: a } { x: null } ] | group-by { get x } | values | length
1

> # Use --to-table to keep null groups
> [ a null ] | group-by --to-table
╭───┬───────┬───────────╮
│ # │ group │   items   │
├───┼───────┼───────────┤
│ 0 │ a     │ ╭───┬───╮ │
│   │       │ │ 0 │ a │ │
│   │       │ ╰───┴───╯ │
│ 1 │       │ ╭───┬──╮  │
│   │       │ │ 0 │  │  │
│   │       │ ╰───┴──╯  │
╰───┴───────┴───────────╯
> [ { x: a } { x: null } ] | group-by x --to-table
╭───┬───┬───────────╮
│ # │ x │   items   │
├───┼───┼───────────┤
│ 0 │ a │ ╭───┬───╮ │
│   │   │ │ # │ x │ │
│   │   │ ├───┼───┤ │
│   │   │ │ 0 │ a │ │
│   │   │ ╰───┴───╯ │
│ 1 │   │ ╭───┬───╮ │
│   │   │ │ # │ x │ │
│   │   │ ├───┼───┤ │
│   │   │ │ 0 │   │ │
│   │   │ ╰───┴───╯ │
╰───┴───┴───────────╯

> # null and empty string stay separate
> [ "" null ] | group-by --to-table | to nuon --raw
[[group,items];["",[""]],[null,[null]]]

> # record output: only "" remains; null is omitted
> [ a "" null ] | group-by | to nuon --raw
{a:[a],"":[""]}
Optional cell paths (unchanged)
> # Missing optional column still skipped
> [{foo: 123}, {foo: 234}, {bar: 345}] | group-by foo?
╭─────┬─────────────╮
│     │ ╭───┬─────╮ │
│ 123 │ │ # │ foo │ │
│     │ ├───┼─────┤ │
│     │ │ 0 │ 123 │ │
│     │ ╰───┴─────╯ │
│     │ ╭───┬─────╮ │
│ 234 │ │ # │ foo │ │
│     │ ├───┼─────┤ │
│     │ │ 0 │ 234 │ │
│     │ ╰───┴─────╯ │
╰─────┴─────────────╯
> # only groups "123" and "234"

> # Optional path with explicit null is also skipped
> [{x: a}, {x: null}] | group-by x?
╭───┬───────────╮
│   │ ╭───┬───╮ │
│ a │ │ # │ x │ │
│   │ ├───┼───┤ │
│   │ │ 0 │ a │ │
│   │ ╰───┴───╯ │
╰───┴───────────╯
> # only group "a"

Fixed scope commands to include local scopes [toc]

PR #18684 by @fdncred

Fixed scope variables, scope commands, scope aliases, scope modules, and scope externs so they report both the current local scope and the global/permanent scope. Nested definitions inside do, if/for bodies, and custom commands now appear while that scope is active (and disappear afterward). Outer variables remain visible inside closures (for example let a = 1; do { let b = 2; scope variables } lists both $a and $b).

After this change

Outer + local variables

let a = 1
do {
  let b = 2
  scope variables | where name in ["$a", "$b"] | sort-by name | select name value
}
# name  value
# $a    1
# $b    2

Local commands / aliases / modules

do {
  def local-cmd [] { "hi" }
  alias la = ls
  use spam.nu   # module file in the cwd
  scope commands | where name == "local-cmd" | length   # 1
  scope aliases  | where name == "la"        | length   # 1
  scope modules  | where name == "spam"      | length   # 1
}
# after the block ends, those local names are gone again

Keyword blocks (IR-inlined)

if true {
  def local-cmd [] { "hi" }
  scope commands | where name == "local-cmd" | length   # 1
}
# after if:
scope commands | where name == "local-cmd" | length     # 0

for loop variable + locals

for i in 1..1 {
  let d = 4
  # scope variables includes $i and $d (and outer globals)
}

Shadowed let

let x = "first"
# scope variables shows $x with value "first" after the first let
let x = "second"
# then shows the live second binding

Fixed source losing visibility of outer variables [toc]

PR #18538 by @fdncred

Fixes the bugs found when a script or REPL input used source to run a .nu file, variables defined before the source call could become invisible inside the sourced file, producing a "variable not found" error.

Example reproducing the bug

lll.nu
let xxx = 'let in script'
source sss.nu

Where sss.nu contains:

print $xxx

Running nu lll.nu would fail with:

Error: nu::shell::variable_not_found

  × Variable not found
   ╭─[sss.nu:1:7]
 1 │ print $xxx
   ·       ──┬─
   ·         ╰── variable not found
   ╰────

The same error could also appear in the REPL after re-declaring a variable:

❯ let xxx = 'value 1'
❯ source sss.nu    # OK: prints "value 1"
❯ let xxx = 'value 2'
❯ source sss.nu    # Error: variable not found

After this change the last statement above would print value 2. See the tests and the issue to see more variations.

Errors for... error make? [toc]

PR #18755 by @Bahex

Not specifying the span for error labels (or not doing so correctly) confusingly fell back to using the record's own span instead:

Before w/o start + end
> open first.nu | nu-highlight
let var = 2
let span = (metadata $var).span

error make {
        msg: "my error"
        label: { text: "two" }
}

> run first.nu
Error: nu::shell::error

  × my error
   ╭─[D:\Projects\nushell\scratch\first.nu:6:9]
 5 │     msg: "my error"
 6 │     label: { text: "two" }
   ·            ───────┬───────
   ·                   ╰── two
 7 │ }
   ╰────
Before w/ start + end
> open second.nu | nu-highlight
let var = 2
let span = (metadata $var).span

error make {
        msg: "my error"
        label: { text: "two", start: $span.start, end: $span.end }
}

> run second.nu
Error: nu::shell::error

  × my error
   ╭─[D:\Projects\nushell\scratch\second.nu:6:9]
 5 │     msg: "my error"
 6 │     label: { text: "two", start: $span.start, end: $span.end }
   ·            ─────────────────────────┬─────────────────────────
   ·                                     ╰── two
 7 │ }
   ╰────

So error make succeeded instead of throwing an error. Well, it did throw an error, the one user was trying to, not the one it should due to error make receiving an invalid argument.

From now on error make will raise an error of its own when receiving an invalid argument.

After w/o start + end
> open first.nu | nu-highlight
let var = 2
let span = (metadata $var).span

error make {
        msg: "my error"
        label: { text: "two" }
}

> run first.nu
Error: nu::shell::missing_required_columns

  × Value is missing required columns.
   ╭─[D:\Projects\nushell\scratch\first.nu:6:9]
 5 │     msg: "my error"
 6 │     label: { text: "two" }
   ·            ───────┬───────
   ·                   ╰── missing `span: record<start: int, end: int>` column
 7 │ }
   ╰────
After w/ start + end
> open second.nu | nu-highlight
let var = 2
let span = (metadata $var).span

error make {
        msg: "my error"
        label: { text: "two", start: $span.start, end: $span.end }
}

> run second.nu
Error: nu::shell::missing_required_columns

  × Value is missing required columns.
   ╭─[D:\Projects\nushell\scratch\second.nu:6:9]
 5 │     msg: "my error"
 6 │     label: { text: "two", start: $span.start, end: $span.end }
   ·            ─────────────────────────┬─────────────────────────
   ·                                     ╰── missing `span: record<start: int, end: int>` column
 7 │ }
   ╰────

Math commands: records with list columns and optional cell paths [toc]

PR #18754 by @fdncred

Fixed reducing math commands on records whose columns are lists (including uneven lengths). For example:

> { alice: [0.1 0.6 0.2], bob: [0.8 0.3 0.2 0.9] } | math avg
╭───────┬──────╮
│ alice │ 0.30 │
│ bob   │ 0.55 │
╰───────┴──────╯

All of the following math commands now accept optional cell paths / columns to operate on only those fields:

Reducing (list cells become a scalar):
math avg, math sum, math product, math max, math min, math median, math mode, math stddev, math variance

Element-wise (list cells stay lists):
math abs, math cbrt, math ceil, math floor, math sqrt, math round, math log

> # Reduce only one column
> { alice: [1 2 3], bob: [4 5 6] } | math avg alice
╭───────┬───────────╮
│ alice │ 2.00      │
│       │ ╭───┬───╮ │
│ bob   │ │ 0 │ 4 │ │
│       │ │ 1 │ 5 │ │
│       │ │ 2 │ 6 │ │
│       │ ╰───┴───╯ │
╰───────┴───────────╯

> # Element-wise on one column
> { alice: [-1 -2 -3], bob: [-4 -5] } | math abs alice
╭───────┬────────────╮
│       │ ╭───┬───╮  │
│ alice │ │ 0 │ 1 │  │
│       │ │ 1 │ 2 │  │
│       │ │ 2 │ 3 │  │
│       │ ╰───┴───╯  │
│       │ ╭───┬────╮ │
│ bob   │ │ 0 │ -4 │ │
│       │ │ 1 │ -5 │ │
│       │ ╰───┴────╯ │
╰───────┴────────────╯

> # Works in const context too
> const data = {alice: [1 2 3], bob: [4 5 6]}
> $data | math sum alice
╭───────┬───────────╮
│ alice │ 6         │
│       │ ╭───┬───╮ │
│ bob   │ │ 0 │ 4 │ │
│       │ │ 1 │ 5 │ │
│       │ │ 2 │ 6 │ │
│       │ ╰───┴───╯ │
╰───────┴───────────╯

Examples for each command:

let rec = { alice: [1 2 3], bob: [4 5 6] }

$rec | math avg alice       # alice: 2
$rec | math sum alice       # alice: 6
$rec | math product alice   # alice: 24
$rec | math max bob         # bob: 6
$rec | math min bob         # bob: 4
$rec | math median alice    # alice: 2
$rec | math mode alice      # alice: [1, 2, 3] modes as list
$rec | math stddev alice    # alice: ~0.82
$rec | math variance alice  # alice: ~0.67

{ alice: [-1 -2], bob: [-3 -4] } | math abs alice | to nuon
# {alice: [1, 2], bob: [-3, -4]}
{ alice: [8 27], bob: [64] } | math cbrt alice | to nuon
# {alice: [2.0, 3.0], bob: [64]}
{ alice: [1.2 2.3], bob: [3.4] } | math ceil alice | to nuon
# {alice: [2, 3], bob: [3.4]}
{ alice: [1.2 2.3], bob: [3.4] } | math floor alice | to nuon
# {alice: [1, 2], bob: [3.4]}
{ alice: [4 9], bob: [16] } | math sqrt alice | to nuon
# {alice: [2.0, 3.0], bob: [16]}
{ alice: [1.2 2.7], bob: [3.1] } | math round alice | to nuon
# {alice: [1, 3], bob: [3.1]}
{ alice: [1 10 100], bob: [1000] } | math log 10 alice | to nuon
# {alice: [0.0, 1.0, 2.0], bob: [1000]}

Existing list, table, number, duration, and range inputs keep their previous behavior when no cell paths are given.

Made error messages more consistent. On the commands that make sense, I added int, float, duration, filesize. On others, product, sqrt, cbrt, and log, only work with ints and floats.

Fixed math max on empty streams [toc]

PR #18772 by @fdncred

Previously the empty list (top) would display and error but the empty stream (bottom) would not. This should now be fixed.

[] | math max
['x'] | each { try { into int } } | math max

Clearer delimiter errors [toc]

PR #18702 by @fdncred

Nushell now reports unclosed and unbalanced delimiters with:

  • The kind of delimiter involved ({, }, [, ], (, ), ", ', >, |, …)
  • Where it opened and where the closer was expected (when known)
  • Help text that suggests a fix, sometimes with a structure hint (e.g. which def or record field is open)

Common mistakes such as forgetting [ before list elements, forgetting ( before a grouped expression, forgetting { after if/while/for/try/match, or writing bare record fields without { point near the mistake instead of only at a distant } or EOF.

Fixed path type treating empty strings as directories [toc]

PR #18785 by @pheenty

"" | path type now returns null instead of "dir"

Fixed passing quoted # strings as script parameters [toc]

PR #18782 by @fdncred

Quotes strings with "#" in them like "#00abcd" are now allowed to be passed as parameters.

Example

test.nu
def main [color: string] {
  $"Your color is ($color)"
}

Pass a hex color as a parameter.

> let myColor = "#000000"
> run test.nu $myColor
Your color is #000000
> run test.nu "#abcdef"
Your color is #abcdef

Fixed config reloads duplicating unnamed keybindings [toc]

PR #18828 by @kronberger-droid

Assigning $env.config.keybindings or $env.config.menus now merges into the defaults rather than replacing them, so $env.config.keybindings = [] and $env.config.menus = [] no longer clear anything. Set event: null on a matching binding to unbind a key.

Other fixes [toc]

  • ls with dc-glob enabled no longer fails when encountering files named literally with glob syntax like *. (#18632)
  • Fixed idx so deleted files and directories no longer appear as live index entries. (#18673)
  • Fixed watched idx import runtimes so filesystem changes appear consistently in listings, find results, status, content search, and watch events. (#18674)
  • Nushell now reports incompatible right-hand-side uses of $in in typed math expressions during parsing, matching the existing behavior for the left-hand side. (#18723)
  • With the dc-glob experimental option enabled ls ** now works again. (#18724)
  • If you have a broken symlink for startup files in nushell, that should not prevent nushell from starting up with defaults. (#18726)
  • Now it's easier to see what the default settings are when you don't have them configured. Show (nearly) all settings in $env.config. If you haven't set any, or launched with nu -n, it will show defaults. (#18747)
  • Fixed generate rejecting null value pipeline input despite working with "empty" pipeline input. (#18751)
  • If you set part of the color config, the defaults for the other parts will still be applied. (#18770)
  • Fixed an issue where saving structured data (like a record or table) to a file with no known serializer (no extension, or an unknown one such as .foo) failed with a cryptic Can't convert to string. Nushell now explains that no serializer matches the file's extension and suggests ... | to json | save <file> or ... | table | ansi strip | save <file>. (#18773)
  • Fixed an issue where stor import --file-name with a path that does not exist created an empty file and discarded the contents of the in-memory database without reporting an error. It now fails with a file not found error and leaves the in-memory database untouched. (#18809)
  • Quotes inside (...) subexpressions of interpolated strings now work: $"('" "')" prints " " instead of becoming an unclosable string. (#18812)
  • Fixed an issue where the icon for a folder with a dot was treated as a file. (#18817)
  • $ans works with TUIs better (#18820)
  • Fixed module item completion for use commands to work without a string for possible items to match against. (#18826)
  • Single semver values do not output as a table anymore (#18834)

Hall of fame [toc]

Thanks to all the contributors below for helping us solve issues, improve documentation, refactor code, and more! 🙏

authorchangelink
@cptpiepmatzRemove all tests that use nu_with_plugins!#18585
@BahexAdd test_value! macro#18582
@m-novotnyFix default configuration links (#18598)#18599
@drbrainAllow PluginCommand::get_dynamic_completion() to use EngineInterface::get_plugin_config()#18587
@sid-6581Fix submodule import in test_docker.nu#18606
@BahexCompleteResult type for working with complete in tests#18604
@Alb-OFuse uniq-by validation and extraction#18507
@BahexUpdate some tests to use the new test infra#18651
@cptpiepmatzUpdate terminal tests#18663
@philocalystUpdates to use CompletionResult#18671
@pyz4Date floor/ceil rounding for durations >= 1day#18696
@rvheldenPass Stack to the IR debugger instruction callbacks#18708
@cptpiepmatzDo not run CI on lower layers of stacked PRs#18720
@ZayanKhan-12Fix devdocs links in AGENTS.md#18721
@cptpiepmatzAdd test binaries as a separate crate#18644
@cptpiepmatzAdd test_*! macro and more assertions to the testing prelude#18647
@cptpiepmatzRemove use_nu_with_plugins from Test#18645
@cptpiepmatzAdd run_multiple to NuTester and update ShellErrorExt#18664
@cptpiepmatzUpdate the table tests#18648
@cptpiepmatzUpdate overlay tests#18658
@cptpiepmatzUpdate modules/mod.rs tests#18652
@cptpiepmatzUpdate parser tests#18668
@cptpiepmatzUpdate hooks tests#18669
@cptpiepmatzRefactor some tests#18712
@cptpiepmatzUpdate some more tests that used nu_repl_code#18649
@cptpiepmatzRefactor most test files that used nu --testbin#18713
@cptpiepmatzUpdate redirection tests#18714
@cptpiepmatzUpdate eval tests#18716
@cptpiepmatzUpdate run external tests#18715
@cptpiepmatzUpdate external commands tests#18717
@cptpiepmatzUpdate internal commands tests#18718
@cptpiepmatzUpdate the help text of test binaries#18739
@cptpiepmatzRefactor open tests#18740
@cptpiepmatzRefactor a handful of tests to use test()#18748
@fdncredUpdate doc_config.nu / tweak explore section#18750
@BahexJob spawn closure should be ran with empty pipeline, not null#18752
@cptpiepmatzStabilize unreliable tests in CI#18756
@cptpiepmatzMore updated tests#18768
@cptpiepmatzRemove nu! and update tests#18776
@fdncredReduce ast footprint, increase ir footprint - phase 0#18808
@brandondongFix configuration book link in README#18831
@kronberger-droidStop stat-ing all of PATH once the external cap is hit#18835

Full changelog [toc]

authortitlelink
@Alb-Operf(filters): fuse uniq-by validation and extraction#18507
@Alb-Operf(str): prepare replace matcher once#18508
@Alb-Operf: avoid cloning binary values#18572
@Alb-Operf: avoid cloning list values#18636
@Alb-Ofix(idx): exclude tombstoned entries#18673
@Alb-Ofix(idx): keep watched imports live#18674
@Alb-Orefactor(idx): remove import/export, keep single live index#18679
@BahexAdd test_value! macro#18582
@BahexCompleteResult type for working with complete in tests#18604
@Bahextake while/until commands can include items after the match#18623
@BahexReplace built-in date floor/ceil commands with nu rewrites#18640
@BahexUpdate some tests to use the new test infra#18651
@Bahexfix(generate): handle null input the same as empty pipeline#18751
@Bahexjob spawn closure should be ran with empty pipeline, not null#18752
@Bahexlines: do not prematurely collect output for string value input#18753
@Bahexfeat(error make)!: raise errors for invalid labels#18755
@Bahexfeat(format duration/filesize): add completions for units#18783
@BahexFix module item completion#18826
@Mrfiregemfeat(any/all): Allow using row conditions alongside closures#18353
@Mrfiregemfix: default left and right prompts respect user color settings#18506
@Mrfiregemfeat(into semver): add cell-path support#18567
@MrfiregemShow deprecation entries in scope commands output#18815
@Totara-thibPin CI actions to commit SHAs and declare workflow permissions#18787
@Tyarel8feat(chunks, first, last, take, drop and skip): arg can now also be a filesize for binary#18511
@Tyarel8fix parse_calls negative number detection#18514
@ZayanKhan-12docs: fix devdocs links in AGENTS.md#18721
@aionescufix(try): only pop error handler if it was pushed by current try block#18519
@alerqueBump pin of transient dependency causing unsound transmute#18581
@app/dependabotbuild(deps): bump crate-ci/typos from 1.47.2 to 1.48.0#18502
@app/dependabotbuild(deps): bump plist from 1.8.0 to 1.10.0#18544
@app/dependabotbuild(deps): bump calamine from 0.35.0 to 0.36.0#18547
@app/dependabotbuild(deps): bump humantime from 2.3.0 to 2.4.0#18548
@app/dependabotbuild(deps): bump bstr from 1.12.1 to 1.13.0#18608
@app/dependabotbuild(deps): bump regex from 1.12.3 to 1.13.0#18609
@app/dependabotbuild(deps): bump open from 5.3.4 to 5.4.0#18610
@app/dependabotbuild(deps): bump aws-credential-types from 1.2.14 to 1.3.0#18612
@app/dependabotbuild(deps): bump actions/labeler from 6 to 7#18687
@app/dependabotbuild(deps): bump actions/setup-python from 6 to 7#18688
@app/dependabotbuild(deps): bump aws-config from 1.8.15 to 1.10.0#18689
@app/dependabotbuild(deps): bump http from 1.4.0 to 1.5.0#18784
@app/dependabotbuild(deps): bump Swatinem/rust-cache from 2.9.1 to 2.9.2#18822
@app/dependabotbuild(deps): bump actions-rust-lang/setup-rust-toolchain from 1.12.0 to 1.17.0#18823
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.85.8 to 2.85.11#18824
@app/dependabotbuild(deps): bump bytesize from 2.4.0 to 2.7.0#18825
@ayax79Lazy and expression support for polars rolling#18730
@brandondongFix configuration book link in README#18831
@cacdufix(save): give actionable error when structured data has no serializer#18773
@cpea2506Bump devicons to 0.6.13#18817
@cptpiepmatzRework our YAML implementation using serde-saphyr#18487
@cptpiepmatzDo not run CI for draft PRs#18584
@cptpiepmatzRemove all tests that use nu_with_plugins!#18585
@cptpiepmatzAlso trigger CI on ready_for_review#18586
@cptpiepmatzAdd test binaries as a separate crate#18644
@cptpiepmatzRemove use_nu_with_plugins from Test#18645
@cptpiepmatzAdd test_*! macro and more assertions to the testing prelude#18647
@cptpiepmatzUpdate the table tests#18648
@cptpiepmatzUpdate some more tests that used nu_repl_code#18649
@cptpiepmatzUpdate modules/mod.rs tests#18652
@cptpiepmatzUpdate overlay tests#18658
@cptpiepmatzUpdate terminal tests#18663
@cptpiepmatzAdd run_multiple to NuTester and update ShellErrorExt#18664
@cptpiepmatzUpdate parser tests#18668
@cptpiepmatzUpdate hooks tests#18669
@cptpiepmatzRefactor some tests#18712
@cptpiepmatzRefactor most test files that used nu --testbin#18713
@cptpiepmatzUpdate redirection tests#18714
@cptpiepmatzUpdate run external tests#18715
@cptpiepmatzUpdate eval tests#18716
@cptpiepmatzUpdate external commands tests#18717
@cptpiepmatzUpdate internal commands tests#18718
@cptpiepmatzRemove --testbin from nu#18719
@cptpiepmatzDo not run CI on lower layers of stacked PRs#18720
@cptpiepmatzUpdate kitest#18727
@cptpiepmatzUpdate the help text of test binaries#18739
@cptpiepmatzRefactor open tests#18740
@cptpiepmatzRefactor a handful of tests to use test()#18748
@cptpiepmatzStabilize unreliable tests in CI#18756
@cptpiepmatzMore updated tests#18768
@cptpiepmatzRemove nu! and update tests#18776
@danielcadevFix RHS pipeline input type checking (issue #18682)#18723
@danielcadevfix(save): serialize structured data to text files#18735
@dmatos2012Add uutils ln command#18571
@drbrainAllow PluginCommand::get_dynamic_completion() to use EngineInterface::get_plugin_config()#18587
@fdncredreorganize nushell configuration#18510
@fdncredThe source command no longer breaks variable visibility#18538
@fdncredAdd matrix commands#18553
@fdncredadd const eval in match arms#18559
@fdncredRevert "Add uutils ln command"#18605
@fdncreddisallow export main from modules with keyword names#18619
@fdncredfix bug where ls with dc-glob would fail with literal * name files#18632
@fdncredadd idx watch command#18639
@fdncredupdate nushell to latest reedline commit#18655
@fdncreddisallow keywords from being shadowed#18662
@fdncredupdate some dependencies#18678
@fdncredbump nushell to latest reedline commit a2c6e124#18681
@fdncredagent.md updates#18683
@fdncredMake scope subcommands report local and global scope#18684
@fdncredupdate fff-search to 0.10.1 and tokio to 1.53.1#18693
@fdncredbump reedline dep to latest commit 7eb9bf2#18695
@fdncredadd splashboard to .gitignore#18701
@fdncredbetter lex/parse errors#18702
@fdncredfix dc-glob ls ** and ls **/*/*/* among other things#18704
@fdncredadd comparison operators to semver like &gt; &lt;, ==#18706
@fdncredadd more consistency with null types#18709
@fdncredfix ls ** when using dc-glob experimental option#18724
@fdncredfix startup with dangling symlinks#18726
@fdncredadd $ans record for storing the last result from the repl#18729
@fdncredmake $env.config show default configuration when not set even with nu -n#18747
@fdncredUpdate doc_config.nu / tweak explore section#18750
@fdncredupdate math commands to handle records and support cell path rest params#18754
@fdncredfix color config fallbacks#18770
@fdncredfix math max empty list vs empty string#18772
@fdncredupdate nushell to latest reedline commit 60d99674#18775
@fdncredupgrade kdl to support --spec 1 or --spec 2#18779
@fdncredbump deps#18780
@fdncredallow parameters with # to be passed#18782
@fdncredupdate uu-utils crates to v0.10.0#18795
@fdncredAllow all built-in commands with --regex to use LRU#18797
@fdncredupdate deps#18802
@fdncredreduce ast footprint, increase ir footprint - phase 0#18808
@fdncredfix: allow semver to have coloring, add --loose flag#18819
@fdncredbug: make $ans work better with TUIs#18820
@fdncredadd cli key to $ans record, rename last_result_size to max_last_result_size#18827
@fdncredfix: single semver output as table instead of value#18834
@fdncredrename $ans.cli to $ans.command#18836
@hexbinoctLex quotes inside interpolated string subexpressions#18812
@ian-h-chamberlainSupport CLI args for commandline (nu -c) scripts#18576
@jakobwsmnnfix: into binary not accepting Duration type as input#18522
@kobihikrici: pin milestone-action to a full commit SHA#18601
@kronberger-droidchore(reedline): bump reedline to latest commit#18685
@kronberger-droidchore(reedline): bump reedline to latest commit 83c17a2#18694
@kronberger-droidBump reedline to e4fe8ed#18798
@kronberger-droidfix(completion): stop the cache reordering the answer it stands in for#18806
@kronberger-droidfix(config): match unnamed keybindings by the key they bind#18828
@kronberger-droidchore(reedline): bump to latest reedline commit 6b9115d#18829
@kronberger-droidchore(reedline): bump reedline to 61715da including helix-mode#18830
@kronberger-droidfeat(config): give helix_select keybindings their own table#18833
@kronberger-droidfix(completion): stop stat-ing all of PATH once the external cap is hit#18835
@kronberger-droidfeat(config): make the visual selection style configurable#18838
@latent-9fix(stor): reject a missing file in stor import instead of discarding the in-memory database#18809
@m-novotnyFix default configuration links (#18598)#18599
@oh-summyfix(help): document list input support for hash md5/sha256#18638
@pheentyadd lacy tool into the list of projects that support nushell#18618
@pheentytreat empty string as an invalid path in path type#18785
@philocalystnon-blocking completions#18334
@philocalystasync prompt updating#18660
@philocalystUpdates to use CompletionResult#18671
@philocalystRework how completer works#18761
@pyz4feat(date): add new commands date floor and date ceil#18620
@pyz4fix: date floor/ceil rounding for durations >= 1day#18696
@rabindra789fix(ps): skip exited processes instead of erroring in ps -l#18542
@rvheldenPass Stack to the IR debugger instruction callbacks#18708
@santhrealFix panic and infinite loop in seq on overflow and zero increment#18596
@sid-6581fix: fix submodule import in test_docker.nu#18606
@skyrocket1643parser: add external shape annotation#18512
@sylvestredocs: credit uutils/coreutils for built-in commands in dev FAQ#18529
@xtqqczzebuild(deps): bump num-bigint from 0.4.6 to 0.4.8#18746
Edit this page on GitHub
Contributors: Piepmatz