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.117.0

Today, we're releasing version 0.117.0 of Nu. This release brings structured output from external commands, a live REPL status line, easier completion generation, new record commands, dotenv support, and reusable type aliases.

Where to get it

Nu 0.117.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]

Less parsing, more piping [toc]

Your favorite command has perfectly good terminal output. Very readable, nice colors, absolutely not a table you can pipe into where. Thanks to @fdncred, the new @structured attribute lets you teach an external command how to provide structured data when you need it, without changing how it looks when you run it on its own.

@structured [--porcelain] { lines | parse --regex '^(?<status>..) (?<file>.+)$' }
extern "git status" []

git status | where status =~ M | get file

Define it once, then get on with your pipelines. A plain git status still gives you Git's usual display, while piping it into a Nushell command adds the arguments and decodes the output for you. More details and examples are here.

The REPL is one step ahead [toc]

Still typing? The REPL already has a few things to say. Thanks to @fdncred, a new status line beneath your input shows parse and type errors before you press Enter. When everything looks good, it shows the command signature with the current parameter emphasized, along with your pipeline's output type.

For expressions built entirely from const commands, it can even give you a preview of the result. Type "a,b" | split row "," and get a little = [a, b] sneak peek. Not quite doing your work for you, but getting suspiciously close. You can choose which parts appear with $env.config.status_line; take a look here.

Easy completions ahead [toc]

Writing out every flag your tools support is probably not how you wanted to spend the afternoon. The new generate completions command from @fdncred can do some of that homework for you, generating Nushell extern definitions and completers from carapace specs, fish or zsh completions, man pages, or even --help text.

Save the generated module, load it, and let Tab take over a bit more of the typing. Depending on the source, that can include subcommands, flag values, Git branches, and more, not just a long list of flags. See how to get your tools set up here.

Less transpose, more records [toc]

Sometimes you have a record and would quite like to keep having a record. No quick trip through transpose, no putting it all back together afterward. Thanks to @fdncred, the new record where, record each, record walk, and record apply commands let you work with fields directly.

Keep only the fields you want, change keys and values together, or walk through nested data to redact passwords and tokens. You can also give different fields their own conversions in one go:

{age: '42', email: 'A@B.COM'} | record apply {age: {into int}, email: {str lowercase}}

They work on table rows too. Take a look at the examples here, and give your transpose pipeline a well-earned break.

at-last.env [toc]

That .env file sitting in your project can finally come along without a homemade parser. Thanks to @fdncred, Nushell now reads and writes dotenv files, including names such as .env.local and prod.env. Loading one is as simple as:

open .env | load-env

Quoted values, multiline values, comments, and variable expansion are supported, without executing commands from the file. Environment conversions now also run when you load variables, so a string PATH becomes a list without the extra conversion dance. Read more about dotenv support and the related environment changes here.

Just my type [toc]

Ever copied the same large record type into three different command signatures? Give it a name instead. Thanks to @fdncred, the new type keyword lets you define reusable type aliases:

type Point = record<x: float, y: float>
type Polygon = list<Point>

def first-x [poly: Polygon]: nothing -> float { $poly.0.x }

Use them in your annotations, build aliases out of other aliases, and export them from modules for other scripts to use. Less repeating yourself, more knowing what that list of records is supposed to represent. More details are here.

Breaking change

type is now a reserved keyword, so commands, aliases, or externs you defined with that name need renaming. To call an external command named type, use ^type; to look up a command in Nushell, use which.

Changes [toc]

Breaking changes [toc]

ps lists every process and reports the same columns on every platform [toc]

PR #19145 by @fdncred

ps now lists every process on macOS (including zombies) and Windows (except the System Idle Process), including other users' and protected processes. Rather than leaving out a process when some information is unavailable, it returns null for those values. On macOS, for example, the CPU, memory and thread values for other users' processes are null unless you run as root.

Both ps and ps -l now return the same columns on every platform, with null for values a platform or process doesn't provide:

  • ps: pid ppid name user status cpu cpu_time mem
  • ps -l adds: virtual private command exe start_time user_id process_group_id session_id priority nice threads read written cwd environment

The new cpu_time column reports total CPU time, while private reports memory used only by that process—the value Activity Monitor and Task Manager show as "Memory". The nice column holds the nice value, or the priority class mapped onto the nice scale on Windows. The read and written columns report bytes of storage I/O since the process started (all I/O on Windows), and exe holds the executable's path. Platforms previously missing user, user_id, process_group_id, session_id, threads, cwd or environment now provide them, as do the BSDs for start_time.

Scripts using the old column layout may need updating: user is now included in plain ps, virtual is only available with ps -l, and process_threads has been renamed to threads. The working column, which always matched mem, and paged have been removed. Use private for memory used exclusively by a process.

On Linux, cpu is now measured to the nanosecond instead of in 10% steps, and name is no longer truncated to 15 characters when argv[0] or the executable provides the full name. For processes you can't read—usually other users' processes unless you are root—cwd and environment are null; cwd previously returned an empty string.

On Windows, ps now reports status as Running, Sleeping or Suspended. The old user_sid column is replaced by user_id, which holds the SID string, such as S-1-5-18. The virtual column now means virtual address space size, matching other platforms, and priority reports the base priority (8 for normal priority). The nice value maps priority classes as libuv and Node.js do: normal is 0, high is -14 and idle is 19. The process_group_id identifies the console process group created with CREATE_NEW_PROCESS_GROUP, to which GenerateConsoleCtrlEvent sends Ctrl+Break.

On macOS, cwd now reports the current working directory rather than the directory where the process started. The status column uses Sleeping instead of Sleep and Waiting, matching other platforms, and reports zombies as Zombie. The kernel_task process (pid 0) is now listed, as in Activity Monitor.

On FreeBSD, NetBSD and OpenBSD, zombies and other processes whose arguments can't be read are now listed under the kernel's process name. FreeBSD's cpu measurement now includes threads that start or exit during the sample, and OpenBSD's virtual value is no longer always 0. On both Windows and the BSDs, command now replaces newlines and tabs in arguments with spaces, as it already did on Linux and macOS.

When filtering or sorting, account for the newly visible null values. Null sorts after every number, so drop nulls before selecting the highest CPU users: ps | compact cpu | sort-by cpu | last 3. Matching a nullable text column with =~ is an error, so similarly use ps | compact status | where status =~ Run.

group-by --to-table keeps original key types [toc]

PR #18853 by @fdncred

group-by --to-table no longer converts group keys to display strings. The group columns keep the original type, and rows are grouped by typed value identity (same type and payload), not by how the value would print.

> [{n: 1} {n: 2} {n: 1}] | group-by n --to-table
╭───┬───┬────────────────╮
│ # │ n │     items      │
├───┼───┼────────────────┤
│ 0 │ 1 │ [table 2 rows] │
│ 1 │ 2 │ [table 1 row]  │
╰───┴───┴────────────────╯
> [[k v]; [a [1]] [b [1]]] | group-by v --to-table
╭───┬───────────────┬────────────────╮
│ # │       v       │     items      │
├───┼───────────────┼────────────────┤
│ 0 │ [list 1 item] │ [table 2 rows] │
╰───┴───────────────┴────────────────╯
> [[size]; [1MB] [1.001MB]] | group-by size --to-table | describe
table<size: filesize, items: table<size: filesize>>

Distinct filesizes that used to share a formatted string (1MB and 1.001MB both display as 1.0 MB) are now separate groups. The group key can be used as a filesize again without str replace / into filesize workarounds:

> [[size]; [1MB] [1.001MB]] | group-by size --to-table
╭───┬────────┬───────────────╮
│ # │  size  │     items     │
├───┼────────┼───────────────┤
│ 0 │ 1,0 MB │ [table 1 row] │
│ 1 │ 1,0 MB │ [table 1 row] │
╰───┴────────┴───────────────╯

Default group-by (record output) is unchanged: keys are still display strings, "true" and true still share a group, and filesize/datetime still follow config. Use --to-table when you need the original type.

This is a breaking change for scripts that assumed --to-table keys were strings (str replace, into filesize after stringify, string compares). "true" and true are now separate --to-table groups.

Retrieve multiple cell paths with get ...$paths [toc]

PR #18220 by @mvanhorn

get now accepts spread cell paths with get ...$paths, returning a list with one value per path whenever a spread argument is used. Its signature changes from get <cell_path> ...(rest) to get ...(rest), so calling get without arguments is no longer a parse error. Instead, it returns its input, or reports Pipeline empty when there is no input.

Pass column names directly to update cells [toc]

PR #19125 by @Shub3am

update cells now accepts column names as rest arguments, matching select, reject, and the into commands. The --columns (-c) flag is deprecated but still works, with a warning on first use. Replace the flag and list with column names after the closure:

# before
[[name val1 val2]; [foo 1 4] [bar 8 3]] | update cells -c [val1 val2] { $in * 2 }
# after
[[name val1 val2]; [foo 1 4] [bar 8 3]] | update cells { $in * 2 } val1 val2

Assigning $env.config.keybindings and $env.config.menus replaces the list [toc]

PR #19418 by @kronberger-droid

Breaking: $env.config.keybindings = [...] and $env.config.menus = [...] now replace the whole list, including nushell's default menus and the keys that open them (Tab and Shift+Tab completion, Ctrl+Space, F1 help, Ctrl+X and Ctrl+Z paging, the Ctrl+R history menu). If your config assigns either list, or sets keybindings or menus inside a $env.config = {...} record, switch to ++= or Tab stops completing. Reedline's own bindings (movement, editing) are not part of the list and stay.

$env.config.keybindings ++= [{ name: my_binding, modifier: control, keycode: char_t, mode: emacs, event: { send: clearscreen } }]

To get the defaults back in a running shell, assign them again from a clean nu -n:

$env.config.keybindings = (^$nu.current-exe -n -c '$env.config.keybindings | to nuon' | from nuon)
$env.config.menus = (^$nu.current-exe -n -c '$env.config.menus | to nuon' | from nuon)

Filtering a list now removes what it drops, and = [] clears either list. When several keybindings bind the same key in the same mode, or several menus share a name, the last one wins. A keybinding's name is only a label, so sharing one between keys no longer warns. To unbind a key that reedline itself binds, add an entry for it with event: null.

Stricter input and argument checks for save, %(...) and plugin call_decl [toc]

PR #19351 by @fdncred

Calls made through save, %($cmd) and a plugin's call_decl now enforce the same input and argument rules as direct command calls. Scripts and plugins that relied on these checks being skipped may need updating:

  • save checks a custom to <ext> converter's input type. A converter whose signature doesn't cover the data now errors instead of running. Built-in to commands reject the same inputs as before, but with Input type not supported instead of their own message. open and http are unchanged, since they hand converters an untyped byte stream.
  • save keeps a custom to <ext> converter's $env changes inside it unless it is def --env, the same as ... | to <ext>.
  • %($cmd) checks its input and arguments as a direct call does. Spreading a list into a command without a rest parameter is an error instead of being silently dropped.
  • A plugin's call_decl checks the input type, including empty input. 'a' | example call-decl uniq now errors with Input type not supported, and example call-decl 'str join' with Pipeline empty.
  • view ir --json no longer has an ast field in ir_block. It was always null.

Embedders and out-of-tree Command implementations

engine::Call::new, Command::requires_ast_for_arguments, engine::Call::positional_nth and the ast fields on calls and arguments are gone. Build an ir::Call with ir::Call::build and run it with nu_engine::eval_ir_call; the PR description has the full migration table. Plugins implementing PluginCommand are not affected.

Other breaking changes [toc]

  • not now has the precedence help operators lists: not $a == $b means not ($a == $b). Before, not applied to the next value only. (#19271)
  • -$x and -(expr) negate their value, also as a flag's value or an argument after --. Before, -$x was the string "-$x" and -(2 + 3) the string "-5". Arguments to external commands are unchanged. (#19271)
  • An integer literal too large for 64 bits, such as 9223372036854775808, is an error. Add .0 to write a float. (#19271)
  • Filesize and duration literals that don't fit are a parse error (nu::parser::literal_too_large) instead of saturating to the largest value. (#19271)
  • A word written like a date that isn't a valid date, such as 2023-02-29, is an error. (#19271)
  • INF, Nan, Infinity and other spellings of special floats are strings. Use inf, nan or NaN. from nuon reads them the same way. (#19271)
  • A record or table literal that names a field twice is a parse error. (#19271)
  • [1 2]] is an error instead of [1, "2]"]. (#19271)
  • In a custom command, repeated parameter or flag names, repeated short flags, a parameter after ...rest, and a --help flag are errors. (#19271)
  • while and loop can't be piped, like for. (#19271)
  • unlet errors on constants and on $in. (#19271)
  • Assigning to a mut variable inside a where condition is an error; the assignment never took effect. (#19271)
  • hide inside a block (do { }, if, a command body) now hides the name only in that block. (#19415)
  • source of a file sourced before in a block that has ended, such as do { source x.nu }; source x.nu, now defines the file's commands and variables again. (#19415)
  • A variable from a sourced file can now be used inside a closure, as in do { source x.nu; $x }. (#19415)
  • run keeps a script's commands, including main, and its variables inside the script. Previously they stayed defined in the caller after run, and a main from run ran a second time when the calling script ended. (#19415)
  • A pipe or redirection in an alias is now a parse error. Previously alias q = ls | length passed | and length to ls as arguments. Use def for a pipeline. (#19415)
  • Scripts, modules and config files that start with a UTF-8 byte-order mark now run. (#19415)
  • Breaking change. Module directories with a dot in their name now keep the full name. use a.b creates module a.b (commands like a.b foo) where it used to create a (a foo). The same goes for overlays, so overlay use a.b now gives overlay a.b. A directory named foo.nu/ is now foo.nu instead of foo. Scripts that call these commands by the short name need updating. (#19390)

Additions [toc]

Work directly with records using the new record commands [toc]

PR #19190 by @fdncred

Added record where, record each, record walk and record apply to filter fields, transform keys and values, process nested values, and apply field-specific conversions without converting records to tables and back. Each command also accepts a table and streams one record per row. Run record to see help listing the subcommands.

The following examples show how to filter and transform records, redact nested values, and convert fields in records or table rows.

> # keep the fields whose value is greater than one
> {a: 1, b: 2, c: 3} | record where value > 1
╭───┬───╮
│ b │ 2 │
│ c │ 3 │
╰───┴───╯
> # keep the fields whose key starts with NU_
> {NU_LOG: debug, HOME: /home/me} | record where key starts-with NU_
╭────────┬───────╮
│ NU_LOG │ debug │
╰────────┴───────╯
> # change keys and values in one pass
> {a: 1, b: 2} | record each {|key, value| {($key | str uppercase): ($value * 10)}}
╭───┬────╮
│ A │ 10 │
│ B │ 20 │
╰───┴────╯
> # redact nested values by their cell path
> {db: {host: prod, password: hunter2}, api: {token: abc}} | record walk {|value, path| if ($path | to text) =~ '(?i)secret|token|password' { '***' } else { $value } }
╭─────┬─────────────────────╮
│     │ ╭──────────┬──────╮ │
│ db  │ │ host     │ prod │ │
│     │ │ password │ ***  │ │
│     │ ╰──────────┴──────╯ │
│     │ ╭───────┬─────╮     │
│ api │ │ token │ *** │     │
│     │ ╰───────┴─────╯     │
╰─────┴─────────────────────╯
> # convert several fields with a reusable record of closures
> {age: '42', email: 'A@B.COM', tags: [x]} | record apply {age: {into int}, email: {str lowercase}}
╭───────┬───────────╮
│ age   │ 42        │
│ email │ a@b.com   │
│       │ ╭───┬───╮ │
│ tags  │ │ 0 │ x │ │
│       │ ╰───┴───╯ │
╰───────┴───────────╯
> # convert a column of every row of a table
> [{name: a, size: '1'} {name: b, size: '2'}] | record apply {size: {into int}}
╭───┬──────┬──────╮
│ # │ name │ size │
├───┼──────┼──────┤
│ 0 │ a    │    1 │
│ 1 │ b    │    2 │
╰───┴──────┴──────╯

record where accepts a row condition on key and value, or a closure receiving the key and value as arguments. Place --keys or --values before the condition to pass only the key or value. Use record walk --containers to also visit nested records and lists, or --no-lists to treat lists as single values. With record apply, --strict reports an error when a transform targets a field missing from the input.

detect type recognizes human-readable durations [toc]

PR #19204 by @sidney3

detect type now recognizes durations in Nushell’s human-readable format, including composite values such as "1hr 3min", and converts them to duration values.

> "1hr 3min" | detect type | describe
duration

Name reusable types with type [toc]

PR #19223 by @fdncred

Nushell now supports type aliases with type Name = <type>, letting you reuse descriptive names instead of repeating type annotations. Aliases can also refer to other aliases, including inside generic types:

type Point = record<x: float, y: float>
type Polygon = list<Point>

def first-x [poly: Polygon]: nothing -> float { $poly.0.x }

Use aliases in parameters, flags, rest and closure parameters, input/output types, and let/mut/const annotations. Help, command introspection, and errors show the expanded type. Completers stay on parameters, as in def paint [color: Color@[red green blue]], rather than on the alias itself.

Define aliases before using them; self-references are not allowed. Aliases are local to a block and persist across REPL lines. Export module aliases with export type, then import them by name, in a list, or with *; a bare use mod does not import them.

type is now reserved. Scripts defining a command, alias, or extern named type fail with "Can't use parser keyword type as command name" until that definition is renamed. On macOS, a bare type ls no longer runs /usr/bin/type; use ^type or Nushell's which.

Custom types in type signatures [toc]

PR #19311 by @ayax79

Custom types, including those from all installed plugins, can now be used in type signatures and resolve correctly in the Nushell LSP. The following examples show custom types used in parameter and input/output type annotations:

def f [v: semver]: semver -> semver { $v }                              │

def ls-df [ ]: nothing -> polars_dataframe {
  ls | polars into-df
}

Catch undeclared flags with extern --strict [toc]

PR #19313 by @fdncred

extern --strict and export extern --strict now reject undeclared flags with a parse error and a "Did you mean" hint for matching declared flags, helping catch typos before running an external command. Positional arguments, -- and the arguments after it still reach the command. --help is always allowed; -h must be declared. Externs without --strict continue to accept undeclared flags.

Unknown flags inside a declared flag's value, as in cmd --x (ls --bogus), are now reported for externs and def --wrapped commands instead of silently dropping the error and passing --x without its value.

Structured data from external commands [toc]

PR #19316 by @fdncred

The new @structured [args] { decode } attribute lets an extern return structured data without repeating output-format flags and decoding commands. When its output is piped into an internal command or saved with let, Nushell adds the specified arguments and decodes the output with the block. At the terminal, through print, when redirected to a file, or when piped into another external command, the tool's own output is unchanged.

@structured [--porcelain] { lines | parse --regex '^(?<status>..) (?<file>.+)$' }
extern "git status" []

git status | where status =~ M | get file   # runs `git status --porcelain` and parses it
git status                                  # git's own text

Running the extern by itself keeps Git's usual display:

> git status
On branch extern_structured
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   crates/nu-cli/src/commands/print.rs
        modified:   crates/nu-cmd-lang/src/core_commands/attr/mod.rs
        modified:   crates/nu-cmd-lang/src/core_commands/do_.rs
        modified:   crates/nu-cmd-lang/src/core_commands/ignore.rs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        crates/nu-cmd-lang/src/core_commands/attr/structured.rs
        crates/nu-command/tests/commands/attr_structured.rs

no changes added to commit (use "git add" and/or "git commit -a")

When piped into an internal command, its output becomes structured data, ready to filter, select, or otherwise process in Nushell:

> git status | where status =~ M
╭────┬────────┬──────────────────────────────────────────────────╮
│  # │ status │                       file                       │
├────┼────────┼──────────────────────────────────────────────────┤
│  0 │  M     │ crates/nu-cli/src/commands/print.rs              │
│  1 │  M     │ crates/nu-cmd-lang/src/core_commands/attr/mod.rs │
│  2 │  M     │ crates/nu-cmd-lang/src/core_commands/do_.rs      │
│  3 │  M     │ crates/nu-cmd-lang/src/core_commands/ignore.rs   │
╰────┴────────┴──────────────────────────────────────────────────╯

Generate external command definitions and completions [toc]

PR #19314 by @fdncred

The new generate completions command generates a module of extern definitions and completers from carapace specs, fish or zsh completions, man pages, or --help text. Save the output and load it with use or source, or place it in an autoload directory:

generate completions git | save ($nu.user-autoload-dirs | first | path join git-completions.nu)

When using use, choose a filename other than the tool's name, such as git-completions.nu. Generated modules provide flag-value and argument completions where the source supports them, including fixed lists, git branches, remotes and tags from fish completers, users and hosts, and native completions from Cobra-based tools such as gh, docker and kubectl.

By default, the first source that knows any flags is used, in the order carapace, fish, zsh, man, then help. Use --source all to merge sources. Carapace, fish and zsh provide subcommand trees; man and help provide flags for the named command. You can also pipe source text, as in ^git status -h | generate completions "git status" --source help.

Flag-name completion also no longer lists a flag twice when an extern with @complete external declares it and the external completer suggests it too.

Smaller table output and ANSI optimization with ansi opt [toc]

PR #19340 by @fdncred

Tables using the default colors now contain fewer escape sequences, reducing output size by 19% for ls, 28% for a nested table, and 43% for a 300-row stream. Their appearance is unchanged, even when an individual line is extracted and printed on its own.

The new ansi opt command shortens ANSI escape sequences in strings, binary data, and byte streams without changing their terminal appearance. Use --stats, --diff, --explain, --hotspot, --show, or --html to inspect the changes as records, tables, visible escape sequences, or an HTML report. Optimization is explicit; Nushell does not automatically rewrite other output at print time.

Custom converters and commands work in more indirect calls [toc]

PR #19351 by @fdncred

Running a command by id now takes the same path as a compiled call, so save, %($cmd), http, open and a plugin's call_decl check input types and bind arguments the way a direct call does.

This also makes custom commands usable in more places. The http commands can now convert a response with a custom from <ext> command, as open already could. When save uses a custom to <ext> converter, it now binds that command's flags and defaults. Plugins can also use call_decl to call a custom command.

Read and write dotenv files with automatic environment conversion [toc]

PR #19391 by @fdncred

Nushell now supports from dotenv and to dotenv. open .env also recognizes names such as .env.local and prod.env, returning a record, while saving a record to these files writes dotenv text. Use open .env | load-env to load variables from a dotenv file.

Dotenv parsing supports quoted and multiline values, comments, optional export, and variable expansion using earlier keys or environment variables, without executing commands. Serialization applies environment string conversions, including joining a PATH list with the path separator, and quotes and escapes values for reading back.

load-env, with-env and FOO=bar cmd now apply $env.ENV_CONVERSIONS to the variables they set, and a string PATH becomes a list. The $env.ENV_CONVERSIONS = $env.ENV_CONVERSIONS line after load-env is no longer needed. Pass --no-convert to set the values as given.

A text file named like .env that isn't KEY=value lines, such as an autoenv shell script, now fails to open with a parse error. Use open --raw .env to read it as text. Recognized extensions retain their formats, so .env.json still opens as JSON. save now matches extensions regardless of case, so save data.JSON writes JSON.

Use first and last in constant expressions [toc]

PR #19399 by @Tyarel8

The first and last commands now work in a const context, allowing you to use them when defining constants. Using last on an unbounded range (e.g. 1.. | last) now returns an error instead of hanging indefinitely.

For example, you can extract a username from your home directory when defining a constant:

# Get username from home directory
const $USER = $nu.home-dir | path split | last

Filter datetimes with older-than and newer-than [toc]

PR #19397 by @fdncred

The new older-than and newer-than operators make filtering by age simpler. ls | where modified older-than 2wk keeps files last changed more than two weeks ago, and newer-than 2wk keeps files changed since then. With a datetime on the right, they work like < and >: $date older-than 2024-01-01. Both comparisons are strict, excluding equality, and are listed in help operators.

Duration comparisons use the current time, so they cannot be used in const, parameter defaults, or match patterns; datetime-to-datetime comparisons remain available there. Either operator returns nothing if either operand is nothing.

Comparing a datetime with a duration using <, <=, > or >= now suggests older-than or newer-than in the error.

Live status line and interruptible math reductions [toc]

PR #19403 by @fdncred

The REPL now shows a status line beneath the line being edited, providing feedback as you type. It displays the first parse or type error or, when there is none, the command signature with the current parameter emphasized, the pipeline's output type, and a preview of lines built only from const commands. For example, "a,b" | split row "," shows = [a, b]. The status line is erased when the line runs.

Use $env.config.status_line to control what appears: enable controls the whole status line, while errors, signature, type, and preview control individual parts.

Ctrl+C now stops math reductions over large ranges, such as 1..10000000000 | math sum, with Operation interrupted. In a script or nu -c, it also stops const evaluations such as const x = (1..10000000000 | math sum).

Other additions [toc]

  • job spawn --auto-kill (-k) marks a job that exit may kill without the "background jobs still running" warning. Jobs without the flag still trigger the warning on the first exit, as before. (#19141)
  • job list has an auto_kill column showing which jobs carry the flag. (#19141)
  • Added a --keep-last/-l flag to uniq, matching uniq-by, to keep the last occurrence of each duplicate value instead of the first. (#19326)
  • into datetime --timezone now accepts all timezones from date list-timezone. (#19139)
  • Added find --only-matching and find -o to return only matched text, similar to grep -o. (#19150)
  • The language server (nu --lsp) now reports its name and version in the LSP initialize response (serverInfo), so editors can show which Nushell version is running. (#19180)
  • Added MCP flags for allowed-hosts and allowed-origins. This is required if you wish to bind the mcp server to other interfaces than localhost. (#19076)
  • path relative-to has a new --walk-up flag that returns a path with .. when the argument path is not a parent of the input: '/a/b/c' | path relative-to '/a/d/e' --walk-up returns ../../b/c. (#19089)
  • into duration rejects odd-length composite fields in the clock format, such as 11:0:22 or 11:000:2 (#19210)
  • Add join --anti, which selects rows not present in the right table by the join column. $lhs | join --anti $rhs ref is equivalent in behavior to $lhs | where ref not-in $rhs. (#19208)
  • On Windows, Nushell now accepts /c and /C as the ComSpec command switch and runs the following command line as Nushell code, improving compatibility when nu.exe is used as ComSpec. This change does not affect other platforms. (#19148)
  • Document in config nu --doc the $env.CMD_DURATION_MS variable and how to use it to determine startup. (#19350)
  • into datetime --formats lists the formats into datetime reads without --format, each with an example: RFC 3339, RFC 2822 and RFC 9557, every date, time and zone layout in the order they're tried, spelling variants such as 18th of April 2025, relative words such as tomorrow 10am, and integer timestamps. Filter it by kind: into datetime --formats | where Kind == date. (#19413)

Performance [toc]

Faster parsing and improved parser diagnostics [toc]

PR #19138 by @fdncred

Nushell now parses real scripts about 1.33x faster, reducing parsing time for REPL input, scripts, modules, configuration files, and the standard library. This shortens startup and script loading without changing how valid code is parsed.

Error reporting is also improved. Invalid break or continue statements in closures or def bodies inside catch or finally clauses are now reported during parsing rather than failing at runtime. The "Extra tokens" error for ls |; ls now points at the ;, and an unclosed list reports its "Unclosed delimiter" error only once.

Inside brackets, # starts a comment only when immediately preceded by whitespace. [voilà#tag] now parses as ["voilà#tag"] instead of producing an "Unclosed delimiter" error. Additionally, def --help foo [] { ... } shows help without defining foo, preventing a later call to foo from crashing the shell. view ir now separates items in list and record patterns with commas.

Faster startup and reliable prompt updates [toc]

PR #19236 by @fdncred

Nushell starts faster and uses about 3 MiB less memory per process on Apple silicon Macs. On all architectures, the startup banner avoids computing the welcome message when it only prints the startup time. Measured startup improvements with the default config are shown below; $nu.startup-time is measured the same way as before.

default config, from ~mainthis PR
launch to first prompt15.70 ms13.10 ms
$nu.startup-time8.03 ms7.36 ms
instructions retired by the first prompt149.3M119.8M

On all architectures, date to-timezone now accepts IANA time zone names in any letter case, for example date now | date to-timezone america/new_york. Previously, some lowercase names were rejected as invalid.

Prompt updates from background jobs using commandline set-prompt are no longer lost when the jobs finish before the prompt is drawn. This applies to jobs started from pre_prompt or env_change hooks or prompt closures such as $env.PROMPT_COMMAND, on all architectures. Calling commandline set-prompt directly in those hooks or closures also updates that prompt, overriding the corresponding segment's prompt-variable value rather than being replaced by subsequent prompt evaluation.

Other performance improvements [toc]

  • Closures that call each, where, update or another command that takes a closure run much faster. (#19394)
  • Calls to built-in commands inside loops and closures are faster. (#19394)
  • into datetime, format date, date humanize and date to-timezone read RFC 3339 date-times (2025-04-18T04:04:32-07:00) several times faster. (#19394)
  • Improved performance when the same module is imported from many places. Nushell no longer re-reads a module's files once for every import path when checking whether a cached module has changed. This especially speeds up parsing and the language server on Windows for libraries whose files import each other. (#19228)

Deprecations [toc]

Deprecated commands, flags, and compatibility support removed [toc]

PR #19382 by @fdncred

Commands and options deprecated in Nushell 0.112 or earlier have been removed. Update affected scripts and custom completers to use their replacements:

  • get, select, and reject no longer accept --ignore-errors (-i). Use --optional (-o).
  • get --sensitive (-s) is removed. Cell paths are case-sensitive by default; add ! after a member to make it case-insensitive.
  • filter is removed. Use where, which accepts the same closures, including closures stored in variables.
  • Custom completer results no longer support positional. Use completion_algorithm: substring instead. A completer returning positional: false now gets prefix matching.

The date format and let-env stubs and removal hints for fetch, post, and benchmark have been deleted. These commands were removed in 2023. let-env FOO = 1 now fails with "Assignment operations require a variable", and date format '%Y' with "Extra positional argument". Use $env.FOO = 1 and format date, respectively. Existing search terms still suggest http get for fetch, http post for post, and timeit for benchmark.

Nushell no longer converts a pre-0.93 plugin.nu into plugin.msgpackz. Setups with only plugin.nu start with no plugins; register them again with plugin add.

default no longer warns when a closure is passed directly as $var, and its help now clarifies the unchanged behavior: default $closure uses the closure itself as the default value, while default { ... } evaluates the closure lazily.

Other changes [toc]

Clearer, correctly aligned char --list output [toc]

PR #19091 by @pickx

char --list now groups alternate names for the same character in a new aliases column, reducing the table from 118 entries to 56 and making it easier to browse. Platform-dependent characters, such as path separators, remain separate entries.

The table also stays correctly aligned when displaying control characters that previously caused misalignment.

dc-glob follows nu-glob's rules in every command, with {a,b} added [toc]

PR #19422 by @fdncred

Experimental option

This feature is behind an experimental option. Run Nushell with --experimental-options=dc-glob or set before running Nushell the environment variable to NU_EXPERIMENTAL_OPTIONS=dc-glob.

With the dc-glob experimental option enabled, globbing now follows nu-glob's rules consistently across commands. Patterns such as rm *, cp *, mv * and du * no longer match dotfiles. Recursive removal also respects the starting directory: rm -r ** no longer reaches the current directory, while rm -r */** removes directories below the top-level ones without removing those top-level directories themselves.

Both ls ** and ls dir/** list directories below the starting point, rather than the starting directory itself, and follow directory symlinks. The glob command now uses the same rules as ls: glob ** and glob dir/** list directories below the prefix, glob **/* lists everything below it, and glob */ lists directories only. The previous wax-specific <x:n,m> repeats and \ escapes are no longer supported.

Brace alternatives such as {a,b} now work in every command, so ls *.{rs,toml} matches both extensions. Braces without a comma remain literal, and arguments without *, ? or [ aren't expanded, leaving ^git show HEAD@{1} unchanged. Since an argument can't start with {, use ./{src,tests}/*.rs for alternatives at the beginning of a path. Paths such as /abs/a]c and a{b} refer to the files they spell.

Exclusion patterns are consistent too: du --exclude '*.txt' once again excludes .txt files at any depth, as it does without dc-glob. Both du --exclude and glob --exclude accept {a,b} alternatives, as does watch --glob.

Malformed patterns such as ***, a** and [a now produce an error. In particular, mistyping rm *** no longer deletes everything below the current directory.

Additional changes [toc]

  • Removed Intel Mac (x86_64-darwin) support from the Nushell Nix flake following its removal from upstream Nixpkgs. Apple Silicon Macs remain supported. (#19173)
  • Added record, table, and list-of-strings examples to str substring --help. (#19354)
  • The bundled SQLite behind query db, into sqlite and stor is now 3.54.0. (#19417)

Bug fixes [toc]

Rest patterns anywhere in match lists [toc]

PR #19172 by @fdncred

match list patterns now support .. and ..$rest at any position, not just the end. Items before the rest pattern match the start of the list, and items after it match the end instead of being silently ignored. Using ..$rest captures the values between them, including an empty list when there are none.

> match [1 2 3 4] { [$first, ..$middle, $last] => $middle }
╭───┬───╮
│ 0 │ 2 │
│ 1 │ 3 │
╰───┴───╯
> let steps = [build done]
> match $steps { [.., "done"] => "finished", _ => "running" }
finished

Using more than one rest pattern in the same list pattern now produces a parse error. Each nested list can have its own rest pattern.

Helix mode: h/l in menus, match commands under m and more text objects [toc]

PR #19175 by @kronberger-droid

In Helix mode, h and l now step through an open menu, and l accepts a history hint, matching the arrow keys and vi's h/l behavior. The new match commands under m let you select inside or around a pair, add a pair around the selection, and delete or replace the nearest pair. The cursor also no longer appears at the start of the next line while the prompt waits for the terminal's position report.

Text object edit commands now accept more values in the keybinding config. Alongside word, bigword, brackets and quotes, object_type accepts individual pairs: parentheses, square_brackets, curly_brackets, angle_brackets, single_quotes, double_quotes and backticks. Custom pairs can be specified as records, such as { left: "|", right: "|" }, and brackets now includes <>.

CutTextObject, CopyTextObject and the new SelectTextObject accept an optional check_next setting, which defaults to true. When the cursor is outside any match, these commands act on the next one. The new AddTextObject and RemoveTextObject commands take object_type, while ReplaceTextObject takes old and new. These three commands require a single pair, so using word, brackets or quotes produces an error.

For example, these keybinding events select inside parentheses, wrap the selection in asterisks, and replace parentheses with square brackets:

{ edit: SelectTextObject, scope: inner, object_type: parentheses }
{ edit: AddTextObject, object_type: { left: "*", right: "*" } }
{ edit: ReplaceTextObject, old: parentheses, new: square_brackets }

Correct cell-path containment checks [toc]

PR #19187 by @fdncred

Fixed in between cell paths to report whether the left path appears as a contiguous sequence in the right path, so [$.x] | each {|p| $p in $.a } is [false] and let p: any = $.b.c; $p in $.a.b.c.d is true. not-in now consistently returns the opposite result. An empty cell path on the left is contained in every cell path and no longer causes Nushell to panic.

The following examples show the corrected behavior, with each left path held in an any-typed variable:

leftin rightmainthis PR
$.a$.atruetrue
$.x$.atruefalse
$.b.c$.a.b.c.dfalsetrue
$.0$.items.0falsetrue
$.a.c$.a.b.cfalsefalse
$.a.b$.afalsefalse
(empty)$.apanictrue

math log rejects invalid bases and NaN input [toc]

PR #19127 by @Master-Norna

math log now rejects bases 1, inf and NaN with an error instead of returning Inf, 0.0 or NaN. Previously, base 1 could produce these results:

Before
> 2 | math log 1
inf
> 1 | math log 1
NaN

These calls now error, consistent with already-rejected bases such as 0:

After
> 2 | math log 0
Error: nu::shell::unsupported_input

  × Unsupported input
   ╭─[repl_entry #1:1:5]
 1 │ 2 | math log 0
   ·     ────┬─── ┬
   ·         │    ╰── value originates from here
   ·         ╰── Base has to be a finite number greater than 0 and not equal to 1
   ╰────

The base error message now reflects the valid range: finite, positive bases other than 1. math log also now errors on a NaN input value instead of silently returning NaN, making invalid calculations easier to detect.

More reliable variance and standard deviation for large numbers [toc]

PR #19108 by @Master-Norna

math variance and math stddev now produce more accurate results for large numbers that are close together, avoiding incorrect zero or negative variances and NaN standard deviations. These examples now produce the correct results:

> [506250000.0 506250001.0] | math variance
0.25
> [506250000.0 506250001.0] | math stddev
0.5
> [1000000000 1000000001 1000000002] | math variance
0.6666666666666666

Both commands also no longer fail with OperatorOverflow when squaring large integers. They instead compute using f64, so integers above 2⁵³ may lose precision and produce approximate results rather than an error, matching the precision trade-off made by math avg. Results remain floats.

Expanded tables no longer hang when nested tables are too wide [toc]

PR #19212 by @fdncred

Fixed table --expand hanging until it ran out of memory, or panicking in debug builds, when a nested table was wider than its containing column. Expanded tables now also use a consistent layout across runs.

Previously, this example panicked in debug builds:

> open Cargo.toml | [ $in ] | table -e -w 183 | ignore
Error:   × Main thread panicked.
  ├─▶ at D:\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\papergrid-0.18.0\src\grid\peekable.rs:985:20
  ╰─▶ attempt to subtract with overflow
  help: set the `RUST_BACKTRACE=1` environment variable to display a backtrace.

The command now renders the table instead:

> open Cargo.toml | [ $in ] | table -e -w 183
╭───┬──────────────────────────────────────────────────────────────────────────────────────┬─────────────────────┬──────────────────────────────┬──────────────────────┬─────╮
│ # │                                       package                                        │        test         │          workspace           │        lints         │ ... │
├───┼──────────────────────────────────────────────────────────────────────────────────────┼─────────────────────┼──────────────────────────────┼──────────────────────┼─────┤
│ 0 │ ╭────────────┬─────────────────────────────────────────────────────────────────────╮ │ ╭───┬───────┬─────╮ │ ╭─────────────┬────────────╮ │ ╭───────────┬──────╮ │ ... │
│   │ │            │ ╭───────────┬──────╮                                                │ │ │ # │ name  │ ... │ │ │ package     │ {record 5  │ │ │ workspace │ true │ │     │
│   │ │ authors    │ │ workspace │ true │                                                │ │ ├───┼───────┼─────┤ │ │             │ fields}    │ │ ╰───────────┴──────╯ │     │
│   │ │            │ ╰───────────┴──────╯                                                │ │ │ 0 │ tests │ ... │ │ │ members     │ [list 43   │ │                      │     │
│   │ │            │ ╭───────────┬──────╮                                                │ │ ╰───┴───────┴─────╯ │ │             │ items]     │ │                      │     │
│   │ │ edition    │ │ workspace │ true │                                                │ │                     │ │ dependencie │ {record    │ │                      │     │
│   │ │            │ ╰───────────┴──────╯                                                │ │                     │ │ s           │ 202        │ │                      │     │
│   │ │            │ ╭───────────┬──────╮                                                │ │                     │ │             │ fields}    │ │                      │     │
│   │ │ rust-vers  │ │ workspace │ true │                                                │ │                     │ │ lints       │ {record 2  │ │                      │     │
│   │ │ ion        │ ╰───────────┴──────╯                                                │ │                     │ │             │ fields}    │ │                      │     │
│   │ │            │ ╭───────────┬──────╮                                                │ │                     │ ╰─────────────┴────────────╯ │                      │     │
│   │ │ license    │ │ workspace │ true │                                                │ │                     │                              │                      │     │
│   │ │            │ ╰───────────┴──────╯                                                │ │                     │                              │                      │     │
│   │ │            │ ╭───────────┬──────╮                                                │ │                     │                              │                      │     │
│   │ │ version    │ │ workspace │ true │                                                │ │                     │                              │                      │     │
│   │ │            │ ╰───────────┴──────╯                                                │ │                     │                              │                      │     │
│   │ │ build      │ scripts/build.rs                                                    │ │                     │                              │                      │     │
│   │ │ default-ru │ nu                                                                  │ │                     │                              │                      │     │
│   │ │ n          │                                                                     │ │                     │                              │                      │     │
│   │ │ descriptio │ A new type of shell                                                 │ │                     │                              │                      │     │
│   │ │ n          │                                                                     │ │                     │                              │                      │     │
│   │ │ documentat │ https://www.nushell.sh/book/                                        │ │                     │                              │                      │     │
│   │ │ ion        │                                                                     │ │                     │                              │                      │     │
│   │ │            │ ╭───┬────────╮                                                      │ │                     │                              │                      │     │
│   │ │ exclude    │ │ 0 │ images │                                                      │ │                     │                              │                      │     │
│   │ │            │ ╰───┴────────╯                                                      │ │                     │                              │                      │     │
│   │ │ homepage   │ https://www.nushell.sh                                              │ │                     │                              │                      │     │
│   │ │ name       │ nu                                                                  │ │                     │                              │                      │     │
│   │ │ repository │ https://github.com/nushell/nushell                                  │ │                     │                              │                      │     │
│   │ │ autotests  │ false                                                               │ │                     │                              │                      │     │
│   │ │            │ ╭────────────┬────────────────────────────────────────────────────╮ │ │                     │                              │                      │     │
│   │ │ metadata   │ │            │ ╭───────────┬────────────────────────────────────╮ │ │ │                     │                              │                      │     │
│   │ │            │ │ binstall   │ │ pkg-url   │ { repo }/releases/download/{       │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ version }/{ name }-{ version }-{   │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ target }.{ archive-format }        │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ pkg-fmt   │ tgz                                │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ ╭────────────┬───────────────────╮ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ overrides │ │            │ ╭─────────┬─────╮ │ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ │ x86_64-pc  │ │ pkg-fmt │ zip │ │ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ │ -windows-m │ ╰─────────┴─────╯ │ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ │ svc        │                   │ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │           │ ╰────────────┴───────────────────╯ │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ ╰───────────┴────────────────────────────────────╯ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ ╭─────────────────┬──────────────────────────────╮ │ │ │                     │                              │                      │     │
│   │ │            │ │ winresour  │ │ LegalCopyright  │ Copyright © 2019-2026 The    │ │ │ │                     │                              │                      │     │
│   │ │            │ │ ce         │ │                 │ Nushell Project Developers   │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ FileDescription │ A new type of shell          │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ FileVersion     │ 0.117.0                      │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ ProductVersion  │ 0.117.0                      │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ │ ProductName     │ Nushell                      │ │ │ │                     │                              │                      │     │
│   │ │            │ │            │ ╰─────────────────┴──────────────────────────────╯ │ │ │                     │                              │                      │     │
│   │ │            │ ╰────────────┴────────────────────────────────────────────────────╯ │ │                     │                              │                      │     │
│   │ ╰────────────┴─────────────────────────────────────────────────────────────────────╯ │                     │                              │                      │     │
╰───┴──────────────────────────────────────────────────────────────────────────────────────┴─────────────────────┴──────────────────────────────┴──────────────────────┴─────╯

Tables no longer add blank lines to accommodate tall cells in columns hidden behind .... Tables ending in a ... column also no longer exceed the terminal width by one or two characters.

join errors when a table has no rows with the join column [toc]

PR #19219 by @fdncred

join now raises a column_not_found error when the input table or the right table has rows but none of them contain the join column. Before, a misspelled column name silently produced an empty result or rows full of null. Empty tables and tables where only some rows lack the column behave as before.

> [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d
Error: nu::shell::column_not_found

  × Cannot find column 'd'
   ╭─[repl_entry #1:1:50]
 1 │ [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d
   ·                                                  ┬
   ·                                                  ╰── no row in the input table has this column
   ╰────
  help: Check the column name. To join a table whose rows lack the column, add it first, for example with     
        `default null <column>`

IPv6 zone IDs in HTTP commands [toc]

PR #19213 by @skyfireitdiy

http get, http post, and the other http * commands now support http:// URLs with IPv6 zone IDs, such as http get 'http://[fe80::13%eth0]', allowing requests to link-local addresses on a specific network interface. The RFC 6874 encoded form, such as [fe80::1%25lo0], is also supported. Plain IPv6 requests such as http get 'http://[::1]:8080/a.txt' now work as well; previously these URLs failed to parse or resolve.

Zone IDs are omitted from the automatic Host header so strict servers can accept these requests; user-provided Host headers remain unchanged. URLs with trailing garbage after an IPv6 address or invalid ports are rejected rather than sending requests to an unintended host or port.

https:// URLs with zone IDs remain unsupported because of a TLS limitation.

tui errors when a closure has no table, tree or select to follow [toc]

PR #19220 by @fdncred

A tui widget with a closure and nothing to follow used to draw empty and hide the piped data. tui run and tui debug now report an error that points at that widget's builder: for example when tui log {|row| ...} has no tui table, tui tree, or tui select to follow, when --from names a widget that has no rows or names the widget itself, or when followers could only follow each other. --data, and --value on tui progress, can no longer be combined with --from or a closure, because the closure's output never showed. A closure now follows a table, tree, or select on another tui tab page when the shown page has none. Inside a child list such as tui split [([a b] | tui table | tui log {|row| ...})], the log now shows the closure's output instead of the piped data.

> 1..5 | each {|n| $"tick ($n)"} | tui label --titlebar "ticks" | tui log { $in } | tui run
Error: nu::shell::error

  × nothing for the closure to follow
   ╭─[repl_entry #1:1:65]
 1 │ 1..5 | each {|n| $"tick ($n)"} | tui label --titlebar "ticks" | tui log { $in } | tui run
   ·                                                                 ───┬───
   ·                                                                    ╰── `log-0` runs its closure on the highlighted row of a table, tree, or select, but none can be followed: a widget never follows its own row, or one that follows it. Add one, or drop the closure
   ╰────
> tui log --data [a b] {|x| $x }
Error: nu::shell::incompatible_parameters

  × Incompatible parameters.
   ╭─[repl_entry #2:1:9]
 1 │ tui log --data [a b] {|x| $x }
   ·         ──────┬─────
   ·               ╰── use either --data or --from/a closure, not both
   ╰────

Fixed crashes from infinite closure recursion [toc]

PR #19229 by @fdncred

Fixed a crash when a closure recursed without end. Closure calls (do, each, where, hooks, and so on) now count toward $env.config.recursion_limit, just like custom command calls. Infinite closure recursion now raises a nu::shell::recursion_limit_reached error instead of crashing Nushell with a stack overflow.

For example, let M = {|x| do $x $x}; do $M $M now produces:

> let M = {|x| do $x $x}
> do $M $M
Error: nu::shell::recursion_limit_reached

  × Recursion limit (50) reached
   ╭─[repl_entry #1:1:9]
 1 │ let M = {|x| do $x $x}
   ·         ───────┬──────
   ·                ╰── This called itself too many times
   ╰────

A recursive custom command that calls itself from inside a closure now uses two levels of the limit per recursion. With the default limit of 50, it stops at 25 levels instead of 50. Raise $env.config.recursion_limit in your config file if you need deeper recursion.

Column names after logical operators in row conditions [toc]

PR #19251 by @fdncred

Row conditions in where, any, all, take while, and other commands now treat bare column names after and, or, or xor as column references rather than strings. This lets you combine column conditions without the previous string-to-boolean or unsupported-operator errors:

[{a: false, b: false}] | where not a and not b   # was a "can't convert string to boolean" error
[{a: true, b: true}] | where a and b             # was "'and' does not work on values of type 'string'"

each reports the closure's error instead of "Eval block failed with pipeline input" [toc]

PR #19252 by @fdncred

When a closure passed to each, par-each, or items fails, Nushell now reports the closure's error. The input value it was processing is shown as an extra source value label. $e.msg in catch is the closure's message, and the error code is the closure error's code instead of nu::shell::eval_block_with_input.

Before
> [1 2] | each {|x| $x / 0 }
Error: nu::shell::eval_block_with_input

  × Eval block failed with pipeline input
   ╭─[repl_entry #1:1:2]
 1 │ [1 2] | each {|x| $x / 0 }
   ·  ┬
   ·  ╰── source value
   ╰────

Error: nu::shell::division_by_zero

  × Division by zero.
   ╭─[repl_entry #1:1:22]
 1 │ [1 2] | each {|x| $x / 0 }
   ·                      ┬
   ·                      ╰── division by zero
   ╰────
After
> [1 2] | each {|x| $x / 0 }
Error: nu::shell::division_by_zero

  × Division by zero.
   ╭─[repl_entry #1:1:2]
 1 │ [1 2] | each {|x| $x / 0 }
   ·  ┬                   ┬
   ·  │                   ╰── division by zero
   ·  ╰── source value
   ╰────

metadata <expr> and stor insert/update record flags now ignore pipeline input instead of erroring [toc]

PR #19254 by @fdncred

metadata <expression> now returns only the argument's span and ignores pipeline input instead of erroring. This allows calls such as [1] | each {|x| let s = (metadata $x).span; $s } and "a" | metadata $in to work even when they receive implicit block input or explicit pipeline input. Without an argument, metadata still reports the input's pipeline metadata.

stor insert --data-record and stor update --update-record likewise use the flag's record and ignore pipeline input instead of failing with "Pipeline and Flag both being used", allowing these calls to work inside blocks.

oneof literals prefer matching types over strings [toc]

PR #19238 by @fdncred

In oneof<...> parameter types, string, path, directory, glob, cell-path, external_arg and any no longer claim a literal that another listed type matches, regardless of their order. oneof<string, list<string>> now parses [foo bar] as a list, and oneof<string, int> parses 5 as an integer rather than a string. This also fixes literal parameter defaults and list elements: [x: oneof<string, int> = 5] now defaults to an integer, and list<oneof<string, int>> parses [1 a] with an integer first element.

Quote literals when you need their original text. With oneof<string, int>, 007 arrives as 7 and 0x10 as 16; with oneof<string, number>, 1.10 arrives as 1.1 and nan as a float. With oneof<string, list<string>>, [0-9] arrives as the list ["0-9"]. This also applies to extern parameters, which pass the converted value to the external command.

Bare words that no other listed type matches still parse as strings. Arguments starting with $, ( or { and parameters declared as plain string are unchanged.

Report missing closure blocks instead of panicking [toc]

PR #19159 by @Monster-GM

Fixed a bug where using a closure created after a job was spawned could crash the job. Nushell now reports Closure cannot be evaluated with a source span and helpful hint instead. Errors from job spawn and debug profile reach the caller's try/catch. For unavailable closures, par-each returns a single error rather than an error per item, and default propagates the error instead of storing it as the default value.

Inspecting or serializing these closures no longer crashes: describe --detailed omits the signature key, to text and to toml --serialize use the existing placeholder string, to yaml --serialize reports closure_block_not_found, and to msgpack and to kdl report conversion errors.

Fixes for numeric string conversion and extreme durations [toc]

PR #19265 by @ymcx

into string no longer crashes when converting i64::MIN, correctly formats negative floats with three digits before the decimal point when using --group-digits, and returns NaN for negative values when an extremely large --decimals value causes the formatting calculation to produce NaN.

into duration no longer overflows or panics when supplied with a value at or below i64::MIN.

Fixed plugin input reads remaining blocked after response completion or output drop [toc]

PR #19171 by @gleb-chipiga

Rust plugin input readers no longer remain blocked on idle producers after a complete response finishes writing or the engine drops its output stream. Cancelled reads report ShellError::Interrupted rather than successful EOF. Returning lazy output alone does not release input.

Plugins that need background input reads after response completion must call set_gc_disabled(true), even if plugin GC is disabled in Nushell's configuration. This setting is plugin-wide and the last write wins, so overlapping calls must coordinate updates. An early output drop still requests input cleanup regardless of this setting.

Input forwarded by the SDK to an engine call is preserved until forwarding finishes or its consumer drops it, preventing early responses or output drops from truncating that input. Other calls and engine-call result readers are unaffected.

Updated handling of Nushell-managed environment variables [toc]

PR #19098 by @pickx

load-env, hide-env, and with-env can no longer change $env.PWD, regardless of casing: names such as Pwd are also rejected. hide-env can no longer hide $env.FILE_PWD or $env.CURRENT_FILE, protecting these Nushell-managed variables.

load-env and with-env, including the shorthand syntax FOO=bar command, can now set $env.config. hide-env can no longer hide $env.config.

detect type preserves whitespace-padded strings [toc]

PR #19299 by @rajaryan0x1

Fixed detect type returning conversion errors for whitespace-prefixed numbers, Unicode digits, and out-of-range integers. Inputs that fail conversion now remain unchanged.

Strings with leading or trailing whitespace, including durations such as " 5ns", now stay strings. Integers with a leading +, such as "+42", are now converted. Numbers with mixed comma and underscore separators remain strings.

try drains a piped stderr before collecting an external [toc]

PR #19339 by @bercedev

Fixed try { ^external } catch { ... } | ignore (also with save --stderr, complete, tee --stderr, and inside do or a custom command) running the catch block with "internal error: stderr should not exist" when the external succeeded. The external's stderr now reaches the next command the same way it does without the try.

With finally, the try doesn't fail that way anymore either, but the result is still turned into a value so finally can see it. The next command gets the external's stdout as a value and its stderr is printed, like for let x = ^external. So save --stderr after try ... finally gets an empty stderr, and complete still says it only works with external commands.

to md preserves row order with differing columns [toc]

PR #19356 by @qodelicious

to md now keeps rows in input order when records have different columns, leaving missing cells empty. For example:

> [{a: 1, b: 2} {a: 3} {b: 4} {a: 5}] | to md
| a | b |
| --- | --- |
| 1 | 2 |
| 3 |  |
|  | 4 |
| 5 |  |

Previously, the {a: 5} row appeared before {b: 4}; it now stays after it.

to md --per-element also preserves input order, grouping only consecutive rows with the same columns so headings stay in place. Records with different columns are no longer incorrectly merged into one table, and strings no longer join record groups by mistake.

Fixed a crash when a later row has an empty column name, as in [{a: 1} {a: 2} {"": 5}] | to md.

Fixes for external-command output in try and o> pipelines [toc]

PR #19349 by @fdncred

Fixed try { ^external } | ... hanging with pipefail enabled when the external wrote more than 64KB, with or without catch.

External output now survives finally: try { ^external } finally { ... } | complete receives stdout, stderr and the exit code. save --stderr, tee --stderr and ignore --stderr also receive the external's stderr, while finally {|v| ... } still receives stdout as a value.

Fixed ^external o> file | complete failing with "Complete only works with external commands". complete now receives stderr and the exit code while stdout goes to the file. save --stderr and tee --stderr capture stderr, and ignore displays it instead of dropping it. When catch handles a failed external whose stderr was going to complete, ignore, save or tee, that stderr is now displayed rather than dropped. This also applies to ignore --stderr, which only receives the catch output.

These before-and-after examples show the fixes:

CommandBeforeAfter
try { $BIG } | str lengthhangs300002
try { $BIG } catch { 'c' } | str lengthhangs300002
try { $BIG | lines } | lengthhangs1
try { ^yes } | lines | first 3hangs[y, y, y]
try { $OUTERR } finally {|v| print ($v | describe) } | completestring, then Complete only works with external commandsstring, then {stdout: "out\n", stderr: "err\n", exit_code: 0}
try { $OUTERR } finally { print fin } | save -f --stderr e.txt o.txte.txt empty, err printedo.txt holds out, e.txt holds err
try { $OUTERR } catch {} finally { .. } | ignore --stderrprints errprints nothing on stderr
$OUTERR o> o.txt | completeComplete only works with external commands{stderr: "err\n", exit_code: 0}, o.txt holds out
$OUTERR o> o.txt | ignorestderr droppederr
try { $FAILERR } catch {|e| print $'caught ($e.exit_code)' } | ignorecaught 3boom on stderr, caught 3
do { try { $FAILERR } catch {} | ignore } e> e.txte.txt emptye.txt holds boom

A try without catch or finally no longer waits for an external whose output continues to the next command, and ignores that external's failure, matching behavior with pipefail disabled. This keeps try { ^cmd | lines } | first 3 lazy and lets try { ^cmd } | complete retrieve the exit code instead of having a failure replace the output with null.

With catch, commands following a failing external inside try now process its output before catch runs, matching behavior outside try and pipelines that already read the whole stream with commands such as length or save. To check the external's exit code before later commands run, insert collect: try { ^cmd | collect | lines | each { ... } } catch { ... }.

The following examples show the resulting output and error-handling behavior:

CommandBeforeAfter
try { ^sh -c 'echo hi; exit 3' | lines } | length01
try { ^sh -c 'echo hi; exit 3' } | linesnull[hi]
try { ^sh -c 'exit 3' } | completeComplete only works with external commands{stdout: "", stderr: "", exit_code: 3}
try { ^false } | describenothingbyte stream
try { ^false }; print afterafterafter
try { ^sh -c 'echo a; exit 3' | lines | each {|x| print $'side ($x)'; $x } } catch { 'caught' }caughtside a, caught
try { ^sh -c 'echo notnum; exit 3' | lines | each { into int } } catch {|e| $e.msg }External command had a non-zero exit codeCan't convert to int.

SQLite errors are no longer silently ignored [toc]

PR #19377 by @hexbinoct

query db now reports SQLite errors, such as failed NOT NULL or UNIQUE constraints, instead of returning an empty list. Queries that fail partway through their rows now report an error instead of silently returning partial results.

Reading a database with open, or one of its tables with get, also reports SQLite errors instead of returning partial results. When open reads the whole database, the error names the table that failed.

Reject command and alias names that Nushell reads as values [toc]

PR #19345 by @passionworkeer

Command and alias names that Nushell reads as a value, such as 0x10, 1_2 or 1sec, are now rejected where they are defined instead of being defined but never callable. Module exports follow the same rule, so a module can no longer export these names.

Command and alias names such as 1k, 1M, 1e or infinity, which Nushell reads as command words, can now be defined and called.

JSON parsing accepts a leading UTF-8 byte order mark [toc]

PR #19383 by @jaeminbird

open and from json now parse JSON starting with a UTF-8 byte order mark (BOM) instead of returning a string or failing with --strict. This supports JSON files written by tools such as PowerShell 5.1 and Notepad. Exactly one leading BOM is ignored; two leading BOMs still fail to parse, and BOMs elsewhere remain content.

Input containing only a BOM now produces null, like empty input, and from json --objects skips BOM-only lines like blank lines. clip paste also parses BOM-prefixed JSON instead of returning it as a string.

Flags now work with dynamic builtin calls [toc]

PR #19404 by @fdncred

%$cmd and %($cmd) now pass flags to the builtin selected at runtime. For example, let cmd = "sort"; [1 3 2] | %$cmd --reverse returns [3, 2, 1]. Record spreads also work for computed flags: %$cmd ...{reverse: true}. Quoted flag-like strings such as "--reverse", or variables holding them, remain positional values.

Unknown flags, flags missing their value, and extra positional arguments now produce errors instead of being ignored. A missing required positional argument produces a missing_positional error, as in a direct call, and a list spread before one produces the same error as run.

Breaking changes to flag handling in dynamic builtin calls

Unquoted flag-like arguments in %$cmd and %($cmd) calls are now interpreted as flags. let cmd = "echo"; %$cmd --foo previously printed --foo but now produces an unknown-flag error, like echo --foo; quote the argument to pass it as a string. The -- separator is no longer passed to the builtin: %$cmd -- --foo now gives --foo, not [--, --foo]. This also affects run-external: let cmd = "run-external"; %$cmd echo -la previously passed -la to echo but now produces an unknown-flag error, like run-external echo -la.

Math reducers now aggregate table columns [toc]

PR #19414 by @fdncred

math sum, math avg, math product, math max, math min, math median, math mode, math stddev and math variance with column arguments now reduce the named columns across all table rows and return one record, equivalent to select <columns> | math <op>. For example, ls | math sum size gives {size: ...} instead of returning the table unchanged. Record input behaves as before: list fields are reduced and scalar fields remain unchanged.

Math reducers now reject table columns containing lists

A table column that holds lists now produces an error, as it does for select a | math sum. Previously, [[a]; [[1 2]] [[3 4]]] | math sum a reduced each row's list to [[a]; [3], [7]]. To retain that row-by-row behavior, use update a { math sum }.

table --collapse keeps rows aligned and respects --width [toc]

PR #19424 by @fdncred

table --collapse now keeps each record's cells aligned when values contain nested lists, nested tables, multiple lines, or text wrapped by --width. Tables also stay within the requested width when using custom table.padding or empty nested lists.

This also fixes alignment for multiline record keys, empty values with zero padding, and the restructured theme, and removes a stray space that shifted some nested values in the none and psql themes.

Invalid keybindings and menus are rejected on assignment [toc]

PR #19438 by @kronberger-droid

Assigning $env.config.keybindings or $env.config.menus now produces an error if an entry can't be read, leaving the old list unchanged. This validation covers a keybinding's modifier, keycode and mode, and a menu's layout, input_mode (or only_buffer_difference) and output_mode. Menus without a layout, such as type: {}, are also rejected. Previously, invalid entries were accepted and failed on every prompt. In config.nu, a rejected assignment stops the lines after it from running.

The new config default command returns the default configuration as a record. Since sourcing a config again appends its ++= entries each time, while = replaces the list and drops the defaults, start from the defaults before adding custom entries to keep the list stable:

$env.config.keybindings = (config default).keybindings
$env.config.keybindings ++= $custom

More date formats and more reliable datetime parsing [toc]

PR #19398 by @fdncred

into datetime, format date, date humanize, date to-timezone and detect type now read more date formats from strings. These include Unix timestamps such as @1745000000, ISO week dates such as 2025-W16-5, ordinal dates such as 2025-108, and Apache log timestamps. IANA time zones can be included in several forms: 2025-04-18 04:04:32 America/New_York, 2025-04-18T04:04:32[America/Chicago] and TZ="Europe/Paris" 2025-04-18 04:04.

Relative dates such as tomorrow 10am, 3 days ago, next friday and 2025-04-18 + 2 days are also supported. These follow GNU date -d conventions rather than date from-human: today means now, including the time of day, and a bare unit such as month or week means one unit from now, whereas date from-human rejects a bare unit. A weekday such as next friday resolves to midnight rather than retaining the current time of day. The phrase in 2 days remains supported only by date from-human.

Timezone handling is more consistent. Offsets such as +0530 keep their minutes, even with a zone name in parentheses after them (+0530 (IST)), and US zone names in RFC 2822 dates, such as PDT and EST, use their own offset instead of local time. Local times at daylight-saving transitions now resolve the same way as times with an explicit IANA zone. In Chicago, for example, the repeated time 2025-11-02 01:30 selects the earlier occurrence, -05:00 rather than -06:00. The skipped time 2025-03-09 02:30 represents the same instant as before, but is now shown as 03:30 -05:00 rather than 02:30 -06:00.

Invalid dates such as 2025-02-30 now produce an error instead of becoming February 28, while February 29, 2000 parses correctly. Strings that previously made into datetime panic, such as 2025-04-18T04:04:32.Z, now either parse or return an error. Two-digit years consistently map to 1969–2068 rather than the 100 years around the current year, so years 69 through 75 now mean 1969 through 1975; 1/1/70, for example, is 1970 instead of 2070.

Some strings are no longer interpreted as dates: decimals such as 3.14, times written with units such as 10h36m28s, POSIX zone offsets such as UTC+3, a month name after a time such as 10:00 DEC, and forms such as 1996.07.10 AD at 15:08:56 PDT. Signed numbers and five-digit numbers, such as -0500 and 10000, are now read as nanosecond timestamps like other integers, rather than as the years 500 and 10000.

Other fixes [toc]

  • inf compares as larger than every finite number, and [1.0 inf] | math max is inf. (#19271)
  • 2.0 in 1.0..2.0 is true, and 2.0 in 1.0..<2.0 is false. (#19271)
  • -0x10, +0b11, +5sec and +1kB are numbers. (#19271)
  • 1 in [1.0] is true. (#19271)
  • {true: 1} and [[1 2]; [3 4]] parse, with the keys "true", "1" and "2". (#19271)
  • (-9223372036854775808) mod -1 is 0. (#19271)
  • if 1 { } reports the same type mismatch as while 1 { }, and an if or while condition that fails while it runs reports its own error. (#19271)
  • 9223372036854775807ns and 9223372036854775807b are exact, and integer filesize and duration literals no longer lose precision. (#19271)
  • A script or nu -c command shows every parse warning once, not only the first. (#19271)
  • Clearer errors for invalid UTF-8 from \x escapes and for unclosed raw strings. (#19271)
  • Reject overflow durations in into duration (#19075)
  • Reject empty duration strings in into duration (#19075)
  • gstat no longer wraps its counts above 65,535. A repository with 70,000 untracked files used to report 4,464. (#19233)
  • When gstat can't read a repository's status (a split or sparse index, a damaged index, or a bare repository), the status counts (idx_*, wt_*, ignored, conflicts) are now -1 instead of 0, so the repository no longer looks clean. The other fields are still filled. (#19233)
  • gstat now fills ignored (an ignored directory counts once) and wt_renamed. A file renamed without git mv now counts as one wt_renamed instead of one wt_deleted plus one wt_untracked, and also as wt_modified if it was edited after the move. (#19233)
  • In a repository with no commits yet, branch shows the branch HEAD points to instead of master or HEAD. (#19233)
  • repo_name is now the name of the working directory in linked worktrees and submodules (it used to be worktrees or modules) and the repository's own directory name for bare repositories. (#19233)
  • The gstat plugin starts faster on systems where it used to link a system libgit2, such as a cargo install on macOS with Homebrew's libgit2. (#19233)
  • Pressing Ctrl-C to stop a foreground command in the REPL no longer kills background jobs from job spawn or frozen jobs. They keep running and stay listed in job list. (#19163)
  • When nu -c or a script exits, including after Ctrl-C, its background jobs are terminated instead of being left behind. Ctrl-C also terminates the jobs of a nu --mcp, --lsp or --dap server. (#19163)
  • exit <code> in nu -i -c "..." or nu -i script.nu now exits with that code. Only the REPL keeps the "press exit again" warning on the first exit with running jobs. (#19163)
  • exit inside a background job's closure now ends that job, instead of printing the REPL warning and continuing. (#19163)
  • Fixed a race where killing a job while it was spawning an external command could leave that process orphaned. (#19163)
  • On Windows, externals started from a job run in their own process group, so Ctrl-C in the console no longer reaches them. Ctrl+Break still does. (#19163)
  • hide now hides type aliases. hide Name hides the type alias Name when no alias or command has that name, and hide <module> Name, hide <module> [Name ...] and hide <module> * hide a module's exported type aliases along with its commands. (#19268)
  • help modules <name> lists the type aliases a module exports, and scope modules has a new type_aliases column with each alias's name, type and type_alias_id. (#19268)
  • type ls and other type statements without = now explain how to write a type alias, and for type <name> they point to which <name> and ^type <name>. (#19268)
  • Fixed the --mcp-host description and example in nu --help. (#19268)
  • The MCP server's list_commands and command_help tools, and the "Did you mean" hint for an unknown command, no longer offer a command that was hidden with hide while another overlay was active. (#19270)
  • command_help now describes the command a name actually runs when overlays shadow or hide commands. (#19270)
  • The MCP server's list_commands and command_help tools list an alias that passes positional arguments with only the parameters left for you to give. alias home = cd ~ is listed as home {flags} instead of home {flags} (path). help home is unchanged and still shows the expansion with cd's usage. (#19270)
  • Match highlighting in the completion menu now lands on the right characters for non-ASCII candidates: ß matched by ss, letters with combining accents, ligatures like ffi, and values containing CRLF. Before, the highlighted positions drifted after such characters. (#19258)
  • A cursor position inside a multi-byte character, as sent by editors and the LSP, is now rounded down to the character boundary instead of failing. (#19258)
  • Completing a command name in a file (nu --ide-complete, nu --lsp) no longer replaces the arguments that follow the cursor. A cursor before a ^ or % sigil gives no command completions, and after the sigil only the typed prefix is matched. (#19258)
  • nu --ide-complete now prints valid JSON, so suggestions containing quotes or backslashes no longer produce broken output. (#19258)
  • run script.nu ...args rejects arguments the script's main doesn't accept: unknown flags, extra positional arguments, flags missing a value, and values of the wrong type. --flag=value now works. (#19272)
  • run doesn't convert values to main's parameter types the way nu script.nu does. Quote a number you pass to a string parameter, as in run x.nu --name "23". (#19272)
  • run's own flags must come before the script path. After the path, -f and --help go to main. (#19272)
  • Flags inside a list spread now stay values, so run x.nu ...$args no longer passes a --foo in $args as a flag. Use a record spread like ...{foo: "23"} instead. (#19272)
  • run counts toward recursion_limit, so a script that runs itself too deeply stops with an error instead of crashing nu. (#19272)
  • Fixed du over-reporting sizes for hard-linked files: a file with multiple hard links is now counted once instead of once per link, on all platforms (Linux, macOS, Windows). (#19283)
  • du --long lists the first-seen link only, matching GNU du -a. (#19283)
  • ls --du now counts a hard-linked file once inside each listed directory, like du does. (#19283)
  • First link wins: when the same file is reachable through multiple hard links, only the first occurrence is counted and listed — e.g. du c b a on three links to one file shows a single row for c. This matches POSIX/BSD/GNU du, but scripts that expect one row per operand will see fewer rows. (#19283)
  • unlet works on constants again. It hides the constant's name for the rest of the block, so a later $name is a parse error. At the top level of a script, config file or REPL line, the name is gone for later lines too. What used the constant before the unlet, like a completion list or a command body, keeps its value. (#19294)
  • Calling unlet indirectly, like %($name) $x, is now an error instead of a crash. (#19294)
  • table and table --expand shrink the widest columns first, so short columns such as keys, names and sizes keep their width next to long text or nested tables. (#19303)
  • metadata set --table-width-priority-columns, which ls and ps also set, now works with table --expand and at every terminal width. A priority column shows wherever it would without the priority, and columns to its right hide to leave it up to a third of the table width. (#19303)
  • table --expand draws a nested table whenever it fits, hiding columns to its right first and collapsing the nested table's own columns behind ..., instead of showing [table N rows]. Nested tables no longer drop columns without a ... marker. (#19303)
  • Tables keep each visible column at least 10 characters wide (or its natural width), hiding columns from the right when they don't fit. Without header_on_separator this shows more columns on narrow terminals; with it, fewer, since columns are no longer squeezed to 4 characters. (#19303)
  • Record keys wrap when a key is too long for the terminal, instead of hiding the values. (#19303)
  • With header_on_separator, headers with CJK characters, emoji or Arabic ligatures are drawn in their own row, so the table border lines up. (#19303)
  • In nu --mcp, $history indices no longer shift when old entries are evicted. An evicted index reads as null, and $history | length counts every result stored in the session. Lowering NU_MCP_HISTORY_LIMIT now trims $history to the new limit. (#19318)
  • nu --mcp now runs evaluate calls one at a time. Before, two calls sent together could get the same history_index, and one call's $history entry and $env changes were lost. (#19318)
  • The MCP server's instructions and tool descriptions now match nushell's behavior for ls vs glob on hidden directories, job spawn --description, command_help output, and \u{...} escapes. (#19318)
  • The evaluate tool description no longer tells agents to avoid large output. Output over the limit already comes back as a note pointing at $history. (#19318)
  • tui widgets now draw on the terminal's own background instead of a near-black fill, so text is readable on light terminals. Set $env.config.tui.surface = { bg: "#121216" } and $env.config.tui.backdrop = { bg: "#08080c" } to keep the near-black fill. (#19375)
  • default in any $env.config.tui color is now the terminal's own color, and surface and backdrop accept a bare color such as "#123456". (#19375)
  • from ods now returns a formula error cell's text (such as #DIV/0!) instead of an empty string, and keeps tabs and line breaks inside cell text. (#19420)
  • Fixed from xlsx crashing nushell or running out of memory on a crafted file. It now reports Could not load XLSX file (RUSTSEC-2026-0436). (#19420)
  • Fixed reading a NUON document whose duration literal overflows, such as [1e30sec], no longer wraps into a negative duration. ms, sec, min and hr now report an error, as day and wk already did. (#19087)
  • Fixed an issue where from nuon failed to load a document starting with a UTF-8 byte order mark, such as one written by PowerShell's Out-File or a Windows editor. (#19157)
  • Fixed to nuon writing corrupt output when --raw and --no-commas were combined; the two flags are now rejected as incompatible. (#19158)
  • Nushell now starts non-interactively when started as an MCP server (nu --mcp). (#19153)
  • The vscode UI no longer hangs after inspecting a variable (#19167)
  • Added support to into string for locales and --group-digits with floating point input. Made the into string rounding match math round. (#19166)
  • No crashes when nu --ide-complete uses an out of range value like "nu --ide-complete -1 a.nu" (#19183)
  • Fixed to nuon --pretty padding table columns wider than their contents require when a cell contains multi-byte characters. (#19165)
  • Pressing Ctrl+O no longer crashes the REPL when $env.config.buffer_editor, $env.VISUAL or $env.EDITOR names an editor that can't be found; the keypress now does nothing. (#19185)
  • Fixed to md producing broken tables when a cell contains a line break; line breaks in table cells are now written as <br>. (#19189)
  • Fixed an issue where rename allowed setting duplicate column names on a table (#19196)
  • Fixed a language server crash when an editor requests symbols for an unopened or closed document. The server now continues to handle later requests. (#19194)
  • Fixed history --clear with sqlite history: it now empties the history database in place instead of deleting the file, so the current session keeps recording history and new sessions no longer fail to start with a "disk I/O error". It also works on Windows while Nushell is running. (#19092)
  • Fixed an issue where repeating clock timestamps were wrongly accepted for into duration (#19073)
  • Defining a command or alias whose name contains consecutive, leading, or trailing whitespace is now a parse error, since such a command could never be called. (#18969)
  • into string with a very large -d value no longer panics; it returns the unrounded value. (#19191)
  • Fixed std/dt datetime-diff returning a negative or incorrect day value when the earlier date is at the end of a month (for example Jan 31 → Mar 1). (#19109)
  • Fixed to nuon writing a raw NUL byte into its output; a NUL is now escaped as \0 and forces quoting, so the output round-trips. (#19161)
  • Fixed an issue where bytes remove --end silently dropped leading bytes (or the whole input) when the pattern was not present in the input. --end removes the last occurrence anywhere in the input, not only a suffix. (#19107)
  • Fixed whoami loading translations for the wrong command, which could make its error messages show up untranslated. (#19144)
  • Fixed an issue where aliasing metadata would break its use in std (#19224)
  • Fixed an issue where lifting a column from a nested record collided with the existing columns, but was nevertheless added to the table by overwriting the existing column. (#19201)
  • open and save no longer fail with an internal "Nushell failed: Can't run alias directly" error when the converter for a file's extension is an alias, such as alias "from jsonc" = from json. They now explain that the converter must be a command and suggest the matching def, for example def 'from jsonc' [] { from json }. (#19205)
  • first --strict and last --strict on an empty list, stream or binary now report nu::shell::access_empty_content ("Cannot access empty content.") instead of a misleading "Row number too large" error. (#19234)
  • tutor conditional description text no longer has wording typos. (#19218)
  • Fixed std/help external fallback so multi-word help targets are passed as separate arguments and % or ^ characters inside command names are preserved. (#19149)
  • Emails with unquoted names are now parsed into name-address records instead of plain strings. (#19257)
  • help <command> now lists an alias of one of its subcommands under the alias's own name, right after the subcommand it runs, with Alias for `...` as its description. After alias st = str trim, help str shows st (alias) - Alias for `str trim` below str trim, where it used to show a second str trim line. A hidden alias is no longer listed, and a script's alias "main baz" = main bar now appears in script.nu --help as script.nu baz (alias). (#19253)
  • help <command> no longer lists hidden subcommands. An alias of a subcommand written over several lines, or containing backticks, now shows on one line with its full expansion. A script's alias mb = main bar now appears in script.nu --help, right after script.nu bar. (#19261)
  • The MCP server's list_commands and command_help tools now name each command the way you call it. An alias such as alias st = str trim is listed as st instead of as a second str trim, command_help st works, and defining the alias no longer replaces str trim's help with the alias's. Module commands are listed under the name use gives them, such as spam foo bar after use spam. (#19262)
  • help hide now describes the required argument as the name of the alias, command, type alias, or module to hide, instead of "Module or module file.". (#19279)
  • The last help tee example now prints 100 lines instead of 10000. (#19281)
  • help into string now explains that into string does not convert binary data: binary input returns an error that points to decode, for example 0x[68 69] | decode utf-8. The error hint for binary input is also clearer. (#19284)
  • The tutor echo intro is now more accurate and mentions that a plain value works the same as passing it to echo. (#19287)
  • Fixed a crash when chunks is given a chunk size too large to allocate, such as 9223372036854775807. (#19286)
  • to xml now disallows setting a negative indentation amount. (#19292)
  • Fixed a crash when last is given a count too large to allocate, such as 9223372036854775807, on byte stream input. (#19295)
  • Running a script whose shebang interpreter is missing now names the interpreter, and a program missing a file it needs (such as a shared library) says so, instead of showing an internal "Could not spawn foreground child" error with a Rust source location. Other errors from starting an external command point at the command and its path. (#19280)
  • Errors about the arguments passed to a script's main (such as a missing positional argument) now show the script name instead of main, when the script name parses as a command. Other names (for example 10kb or it's.nu) still show main. (#19282)
  • Fixed a crash when window is given a window size too large to allocate, such as 9223372036854775807. (#19288)
  • Fixed a crash when table --abbreviated is given a row count too large to allocate, such as 9223372036854775807. (#19296)
  • Previously, the version check command would say you are on the latest release if the lookup failed, now, lookup errors will result in an error on the command too. Also, if a github token is available on the environment (GITHUB_TOKEN or GH_TOKEN) it will be used for the request to bypass the unauthenticated 60-requests-per-hour github api rate limit. (#19298)
  • Fixed a panic when using roll up, roll down, roll left or roll right on an empty list or record. (#19285)
  • Fixed an issue where print hid the failure of an external command: a failing external command piped into print now makes the pipeline fail with its non-zero exit code instead of exiting with 0. This is a behavior change for scripts that relied on the old result, for example ^grep pat file | print with no match now errors, and do -i { ^false } | print now fails like do -i { ^false } | collect already does. (#19260)
  • External command arguments containing ... inside a path component (e.g. origin/main...) are no longer rewritten with backslashes on Windows. (#19333)
  • On Windows, cd d:, cd d:folder and just typing d: (auto-cd) now work. If you're already on that drive you stay where you are. Otherwise you land in that drive's current directory from the parent shell, or its root. (#19332)
  • Fixed stale prompt interrupts affecting completions, transient prompts, and the next interactive command with its pre-execution hooks (#19337)
  • Fixed negated character classes in the experimental dc-glob backend: patterns such as [!f]* now exclude names beginning with f. (#19309)
  • Fixed Tab replacing a partly typed subcommand with a file name, such as git re<Tab> becoming git README.md in a directory that has a README.md. (#19344)
  • Fixed dirs drop changing the working directory when the directory list has only one entry. It now leaves you where you are. (#19355)
  • Fixed terminal directory tracking for directory names containing #, ?, %, or ;. UNC paths now report the file server as the host, so terminals that require a local host may ignore them. (#19358)
  • into int and into float conversion errors now name the right direction (can't convert string to int), point at the input value rather than the command, and carry the parse reason as help text. (#19363)
  • split column now rejects duplicate column names with a column_defined_twice error pointing at both uses, instead of silently overwriting the earlier column. (#19362)
  • fill --alignment now errors on an unknown alignment instead of silently left-aligning; valid values are left, right, center/middle and centerright/middleright. (#19361)
  • Fixed explicit relative paths in experimental dc-glob: patterns such as ./*.txt, ../*.txt, and ../** now search the intended directory. Exact paths such as . and .. also return their matching directory. (#19348)
  • Fixed a type mismatch error when a let without a type annotation gets a list from chained update calls on a custom command's output. (#19379)
  • Ranges with invalid step sizes don't cause an overflow anymore (#19385)
  • Duplicate-key errors from record literals that use ... spreads now point at the right places. For let a = {s: 1}; {...$a, s: 3}, the error underlines s: 3 as the redefinition and ...$a as where s was first defined, instead of the whole record and the original {s: 1}. These errors also explain that a record literal can't repeat a key, even one brought in by a spread, and suggest merge or update to replace a field. (#19352)
  • Fixed update cells hiding errors from its closure. An error inside the closure is now raised instead of being stored as the cell value. (#19389)
  • rm no longer removes hidden files through a glob, at any depth, unless the pattern starts a name with . or --all is given. Before, rm **/*.txt also removed .txt files inside hidden directories, and with the dc-glob experimental option rm * removed dotfiles. (#19421)
  • grid now uses layouts that fill the full width, so it no longer errors on a grid that fits exactly and can print fewer rows. (#19409)
  • date to-timezone preserves seconds in numeric offsets such as +05:30:15 and rejects invalid suffixes and separators such as +05:30XYZ, +05:, and +05:::30. Historical time zones with second-level offsets round correctly with date floor and date ceil. (#19434)

Reedline 0.53.0 [toc]

Reedline 0.53.0, the line editor behind Nushell's REPL, brings improvements to menus, history navigation, external editors, and terminal rendering. The live status line and Helix match commands described above are built on this release too.

Editing, menus, and history [toc]

  • Completion menus support mouse selection: clicking an entry highlights it without accepting it or closing the menu. Columnar and IDE menus can move a screenful at a time with PageUp and PageDown. (#1260, #1253)
  • Outside a menu, PageUp jumps to the oldest history entry matching the typed prefix, and PageDown returns to the draft. (#1281)
  • In Emacs mode, Alt+C now capitalizes the word under the cursor, uppercasing its first character and lowercasing the rest, rather than capitalizing only one character. Shift+Backspace now works like Backspace in Emacs and vi insert modes. (#1280, #1264)
  • Buffer-editor commands support {file}, {line}, and {col} placeholders, allowing an editor to open at the current cursor position. Without {file}, the temporary file's path is still appended. Terminal modes are restored after the editor exits, fixing Ctrl+C after opening Helix or Neovim on Windows. (#1041, #1258, #1267)
  • Auto-pairs no longer enter menu search queries, and new opt-in hinter and highlighter hooks allow history hints before trailing auto-pair closers. (#1239, #1244)
  • Partial completion now considers all suggestion spans instead of choosing only the first group. List menus also request the completion count and page together, avoiding duplicate calls to completers that implement only complete. (#1261, #1266)
  • Word-end motions now respect the active caret: they stop after the word with a bar caret, or on its last grapheme in vi and Helix normal modes. Vi also repaints whenever its mode changes. (#1292, #1256)

More reliable terminal rendering and history [toc]

  • Control characters in the buffer, hints, menus, and history are displayed as caret notation, such as ^[ and ^M, instead of being sent to the terminal. Newlines and tabs are preserved; prompts and external-printer output remain raw. (#1241)
  • External messages are printed above the prompt, with the message and redrawn prompt committed in one synchronized frame. Very large completion menus and menu layout after scrolling are also handled more reliably. (#1257, #1243, #1254)
  • Multiline hints show the continuation indicator on every line. The cursor is hidden before querying its position to reduce flashing, and terminals with zero or one row no longer cause a panic. (#1288, #1233, #1236)
  • File-backed history falls back to an unlocked write when the filesystem cannot lock the file, such as NFS without a lock daemon. Updating the last command's context after a read that did not submit now reports “No command run” instead of overwriting an older history entry. (#1286, #1245)
  • Batched input treats Ctrl+J as a line ending, preserving subsequent piped lines. Esc now lets a fallback keybinding run when there is no menu or selection to cancel. Registering a menu under an existing name replaces it instead of adding an unreachable duplicate. (#1263, #1285, #1294)

For applications embedding Reedline [toc]

These Rust API changes concern applications using Reedline directly, not Nushell scripts or plugins:

  • Breaking: Signal::CtrlC is now Signal::CtrlC(String), carrying the buffer before it was cleared. In reverse history search, this is the line from before the search, not the query. Update matches to Signal::CtrlC(buffer) or Signal::CtrlC(_). (#1290)
  • Breaking: HistoryTimestamp replaces chrono types in the public history API. Use from_millis, to_millis, or now; serialized HistoryItem::start_timestamp values are integer milliseconds rather than RFC 3339 strings. DefaultPromptSegment::CurrentDateTime is replaced by Dynamic(fn() -> String), and the default right prompt is now empty. (#1248)
  • Exhaustive event matches need FirstHistory and LeaveHistory; exhaustive edit-command matches need CapitalizeWord. MoveWordRightEnd is deprecated in favor of MoveWordRight. (#1281, #1280, #1292)
  • with_status_line(Box<dyn StatusLine>) adds text below the buffer and hints. Custom menus should account for Painter::remaining_lines and remaining_lines_real excluding the reserved status rows. (#1268)
  • The external printer no longer requires a feature flag. with_external_printer accepts any ExternalOutput; the old external_printer feature remains as an empty compatibility flag. (#1257)
  • New opt-in paste interception and burst-detection hooks let hosts handle clipboard pastes or detect pasted input from key timing, so a pasted Enter can insert a newline instead of submitting. (#1132)
  • EditorCommand exposes buffer-editor template rendering, EventStatus is exported for custom edit modes, and Menu gains default selection_at and set_selection methods for mouse support. (#1258, #1279, #1260)

See the full Reedline changelog for all changes and contributors.

Notes for plugin developers [toc]

Deprecated APIs removed for plugin authors

Several deprecated Nushell APIs have been removed. Plugin authors using these APIs need to update their code to the available replacements:

  • Replace ShellError::GenericError with ShellError::Generic(GenericError).
  • Replace PipelineData::metadata() with metadata_ref(), metadata_mut(), or take_metadata().
  • Replace EngineState::current_work_dir() and StateWorkingSet::get_cwd() with EngineState::cwd() or cwd_as_string().
  • Replace ast::Call::positional_nth() and positional_len() with positional_iter().
  • The unused ShellError::DeprecationWarning is removed.

CustomValue::is_iterable() is no longer deprecated and remains available.

New comparison variants

nu_protocol::ast::Comparison has two new variants, OlderThan and NewerThan. A match on Comparison without a wildcard arm needs arms for them, and CustomValue::operation receives them when a custom value is on the left.

Hall of fame [toc]

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

authorchangelink
@cptpiepmatzUpdate CI artifact uploading#19106
@fdncredImpl Hash for Value and inner types in nu-protocol#18933
@hustcerPreserve warnings in nightly release builds#19232
@fdncredDrop the shared short flag that #19271 made a parse error#19274
@ayax79Fix polars test breakages#19317
@ayax79Added the local_socket feature for nu-plugin-test-support for formats…#19319

Full changelog [toc]

authortitlelink
@4RH1T3CT0R7Reject command names with irregular whitespace at definition time#18969
@Adnan-Husaynfeat(lsp): report serverInfo in the initialize response#19180
@GhostCoder6969Fix it-if typo in chained error doc comment#19143
@Huang-404-Qfix(nu-term-grid): accept a grid that is exactly as wide as the limit#19409
@KissakiFix conditional tutor text typos#19218
@Master-Nornafix(bytes remove): keep input unchanged when --end pattern is not found#19107
@Master-Nornafix(math variance): use a numerically stable two-pass formula for numbers#19108
@Master-Nornafix(std/dt): compute the day remainder directly in datetime-diff#19109
@Master-Nornafix(math log): reject invalid bases and a NaN input value#19127
@Monster-GMfix: report missing closure blocks instead of panicking#19159
@Sha1rholderRemove x86_64-darwin target in flake.nix#19173
@Shub3amTake update cells columns as rest arguments and deprecate --columns#19125
@SyedYousufFaizanFix(LSP) lsp crash on symbol requests for unopened or closed documents#19194
@Tyarel8fix(version check): propagate error and use github token#19298
@Tyarel8feat(docs): document $env.cmd_duration_ms and how to check for startup with it#19350
@Tyarel8feat: make first and last const#19399
@aakarshitvUse whoami's own uucore locale in the whoami command#19144
@akasakarikoPreserve REPL background jobs on Ctrl-C and clean up jobs on non-REPL exit#19163
@akasakarikoReset stale REPL interrupts before running a new command#19337
@akshitj11fix(cli): accept /c as commands flag#19148
@akshitj11fix(std/help): preserve external help arguments#19149
@akshitj11feat(find): add only matching output flag#19150
@app/dependabotbuild(deps): bump similar from 3.1.0 to 3.2.0#18905
@app/dependabotbuild(deps): bump xxhash-rust from 0.8.15 to 0.8.19#19155
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.21 to 2.87.24#19177
@app/dependabotbuild(deps): bump hustcer/setup-nu from 3.27 to 3.28#19178
@app/dependabotbuild(deps): bump uuid from 1.26.0 to 1.27.0#19179
@app/dependabotbuild(deps): bump unicase from 2.9.0 to 2.10.0#19240
@app/dependabotbuild(deps): bump lean_string from 0.7.0 to 0.8.0#19241
@app/dependabotbuild(deps): bump actions/upload-artifact from 7.0.1 to 7.0.2#19242
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.24 to 2.87.27#19243
@app/dependabotbuild(deps): bump vedantmgoyal2009/winget-releaser from 4ffc7888bffd451b357355dc214d43bb9f23917e to b7370d4d152efdce803a26cc6ca9eee58cb2ad54#19244
@app/dependabotbuild(deps): bump uuid from 1.27.0 to 1.28.0#19245
@app/dependabotbuild(deps): bump crate-ci/typos from 1.50.3 to 1.51.1#19246
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.27 to 2.87.29#19304
@app/dependabotbuild(deps): bump tango-bench from 0.8.0 to 0.9.0#19305
@app/dependabotbuild(deps): bump serde-saphyr from 1.3.0 to 2.0.0#19306
@app/dependabotbuild(deps): bump arboard from 3.6.1 to 3.7.0#19307
@app/dependabotbuild(deps): bump hustcer/setup-nu from 3.28 to 3.29#19364
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.29 to 2.87.31#19365
@app/dependabotbuild(deps): bump actions/setup-python from 7.0.0 to 7.1.0#19366
@app/dependabotbuild(deps): bump Swatinem/rust-cache from 2.9.2 to 2.9.3#19367
@app/dependabotbuild(deps): bump uuid from 1.28.0 to 1.29.0#19368
@app/dependabotbuild(deps): bump fancy-regex from 0.19.0 to 0.20.0#19370
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.31 to 2.89.0#19425
@app/dependabotbuild(deps): bump rstest from 0.27.0 to 0.28.0#19426
@app/dependabotbuild(deps): bump brotli from 9.0.0 to 9.1.1#19427
@app/dependabotbuild(deps): bump aws-config from 1.12.0 to 1.13.0#19429
@app/dependabotbuild(deps): bump mq-markdown from 0.9.2 to 0.10.0#19430
@armadavalorfix(cd): resolve Windows drive-relative paths like d: the way cmd does#19332
@armadavalorfix: don't rewrite path separators for external args that merely contain ...#19333
@ayax79MCP: Added allowed-hosts and allowed-origins flags#19076
@ayax79Allow Custom Types to be used in type signatures#19311
@ayax79Fix polars test breakages#19317
@ayax79Added the local_socket feature for nu-plugin-test-support for formats…#19319
@bercedevfix(try): drain a piped stderr before collecting an external#19339
@bfrenOptimize module reloading check#19228
@carlos-mercadodocs: add record, table, and list-of-strings examples to str substring#19354
@cptpiepmatzUpdate CI artifact uploading#19106
@cptpiepmatzAllow TZ_VARIANTS in into datetime --timezone#19139
@cptpiepmatzPrep patch release#19154
@cptpiepmatzAfter patch release#19156
@draconachtupdate eml-parser version to 0.1.6#19257
@eugenesvkUse builtin command sigil to avoid bugs when user aliases shadow builtin#19224
@fdncredgroup-by --to-table keep original types#18853
@fdncredimpl Hash for Value and inner types in nu-protocol#18933
@fdncredperf(parser): parse real scripts about 1.3x faster#19138
@fdncredfix(ps): list every process and report the same columns on every platform#19145
@fdncredbmp rust toolchain to 1.97.1#19160
@fdncredminor updates to AGENTS.md and CONTRIBUTING.md#19164
@fdncredfix(match): allow .. and ..$rest anywhere in a match list pattern, like Rust#19172
@fdncredfix(cell-path):in and not-in between cell paths, and a panic on an empty cell path#19187
@fdncredrecord family of commands#19190
@fdncredfix(table): stop table --expand hanging when a nested table is wider than its column#19212
@fdncredfix(join): error when a table has no rows with the join column#19219
@fdncredfix(tui): error when a closure has no table, tree, or select to follow#19220
@fdncredAdd type aliases with a type keyword#19223
@fdncredfix: count closure calls toward recursion_limit so infinite closure recursion errors instead of crashing#19229
@fdncredfix(gstat): stop wrapping counts and reporting unreadable status as clean, fill ignored and wt_renamed, link libgit2 statically#19233
@fdncredBump locked dependencies to clear the RustSec audit#19235
@fdncredFaster startup: chained fixups on Apple silicon, a cheaper banner, and async prompt pushes that survive#19236
@fdncredfix(parser): try string last in oneof so oneof&lt;string, list&lt;string&gt;&gt; parses [a b] as a list#19238
@fdncredBump rustls to 0.23.46 to clear the RustSec audit#19249
@fdncredfix(parser): treat a bare word after and/or/xor in a row condition as a column#19251
@fdncredfix(each): report the closure's error instead of "Eval block failed with pipeline input"#19252
@fdncredfix(help): list an alias in a command's subcommands under its own name#19253
@fdncredLet metadata &lt;expr&gt; and stor insert/update record flags ignore pipeline input instead of erroring#19254
@fdncredfix(help): drop hidden subcommands and fix multi-line, backticked, and script alias entries#19261
@fdncredfix(mcp): list and look up commands by the name they're called by#19262
@fdncredfix(cli): correct the --mcp-host help text and example#19268
@fdncredfix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes#19270
@fdncredFix the bugs found by the nu-conformance open questions#19271
@fdncredfix(run): reject script arguments that main doesn't accept#19272
@fdncredIgnore the zip extraction advisories in cargo audit, since calamine never extracts#19273
@fdncredtest(run): drop the shared short flag that #19271 made a parse error#19274
@fdncredfix(unlet): hide a constant's name instead of rejecting it#19294
@fdncredfix(table): shrink the widest columns first and honor width priorities everywhere#19303
@fdncredBump webpki crates to clear the RustSec audit#19308
@fdncredAdd extern --strict to reject undeclared flags#19313
@fdncredAdd generate completions to auto-generate extern definitions, with completions, from carapace, zsh, fish, man pages and --help#19314
@fdncredAdd @structured attribute so an extern can return data#19316
@fdncredfix(nu-mcp): keep $history indices stable, run evaluations one at a time, and correct stale guidance in the MCP instructions and AGENTS.md#19318
@fdncredRemove file accidentally committed#19331
@fdncredShorter table escape sequences, and a new ansi opt command#19340
@fdncredDon't let Tab's partial completion drop suggestions that replace a different span#19344
@fdncredFix try hanging under pipefail, and keep an external's stderr through finally and o&gt;#19349
@fdncredRun commands found by id through one IR call path (AST migration phase 3)#19351
@fdncredBump webpage and zstd-sys, ignore the other zstd advisories to clear the RustSec audit#19359
@fdncredbump scraper to 0.29.0, lru to 0.19.0, calamine to 0.37.0#19373
@fdncredfix(tui): draw on the terminal's own background by default#19375
@fdncredKeep list&lt;any&gt; in the inferred output of update on a union with a custom type#19379
@fdncredBump libz-sys to 1.1.31 to clear RUSTSEC-2026-0418#19381
@fdncredRemove deprecations older than six months#19382
@fdncredAdd from dotenv and to dotenv, and have load-env and with-env convert what they set#19391
@fdncredMake closures that call commands faster, and into datetime on RFC 3339 strings#19394
@fdncredAdd older-than and newer-than operators for datetimes#19397
@fdncredReplace dtparse with a jiff-based date reader#19398
@fdncredA status line under the prompt: errors, signatures, types and const previews as you type#19403
@fdncredPass flags through %$cmd dynamic builtin dispatch#19404
@fdncredUpdate ci.yml with incredibuild-macos-latest#19405
@fdncredUpdate Cargo.toml for __eh_frame section warning#19412
@fdncredAdd into datetime --formats to list the formats it reads#19413
@fdncredmath sum size and the other math reducers sum a table's column#19414
@fdncredFix the nu-conformance open questions A1, P1, H1 and R1, and two source bugs#19415
@fdncredBump calamine to 0.38.0 to clear the RustSec audit#19420
@fdncredrm never lets a glob match a hidden file unless asked#19421
@fdncreddc-glob follows nu-glob's rules in every command, with {a,b} added#19422
@fdncredtable --collapse lines up rows and stays within --width#19424
@feiiiiii5fix(nuon): error on a duration head that overflows#19087
@feiiiiii5Strip one leading byte order mark in from nuon#19157
@feiiiiii5Reject to nuon --raw --no-commas, which writes no separator#19158
@feiiiiii5Escape NUL as \\0 in nuon output instead of writing a raw byte#19161
@feiiiiii5Measure nuon table column widths in runes, not bytes#19165
@gleb-chipigaRelease plugin inputs on response completion or output drop#19171
@hexbinoctReport SQLite errors from query db#19377
@hsdfatClear sqlite history with SQL instead of deleting the file#19092
@hustcerfix(ci): preserve warnings in nightly release builds#19232
@intertermux-codefix(du): count a hard-linked file once, not once per link#19283
@itsF4LCONopen/save: give a clear error suggesting def when the from/to converter is an alias#19205
@jaeminbirdStrip one leading byte order mark in from json#19383
@jaideeppynetest(parser): pin exact whole-number unit literals and scaled overflow#18898
@kronberger-droidtest(config): compare canonical paths in test_default_config_path#19044
@kronberger-droidchore: bump reedline to e9fcfdb#19175
@kronberger-droidfix(nix): take libx11 instead of the deprecated xorg set#19181
@kronberger-droidchore: bump reedline to d704744#19202
@kronberger-droidchore: bump reedline to 39db5e3#19290
@kronberger-droidchore: bump reedline to c8d81b2#19342
@kronberger-droidchore: bump ctutils, tokio and clipboard-win to clear the RustSec audit#19343
@kronberger-droidchore: bump reedline to 4a3dad3#19401
@kronberger-droidchore(reedline): bump reedline to 8bc5cd0#19416
@kronberger-droidchore(deps): bump rusqlite to 0.41.1 and reedline to 4fcf4fb#19417
@kronberger-droidfix(config)!: make assigning keybindings and menus replace the list#19418
@kronberger-droidfix(config): reject a keybindings or menus list with an entry it can't read#19438
@latent-9fix: reject out-of-range decimals in into string#19191
@manish-9245fix(print): surface external failures instead of masking exit code (#19227)#19260
@manoj-1407Fix roll panic on empty lists and records#19285
@manoj-1407Fix chunks crash when the chunk size is too large to allocate#19286
@manoj-1407Fix window crash when the window size is too large to allocate#19288
@manoj-1407Fix last crash when the count is too large to allocate#19295
@manoj-1407Fix table --abbreviated crash when the row count is too large to allocate#19296
@maxim-uvarovPath relative to walkup#19089
@mirsellaFix OSC 7 directory URL escaping#19358
@mvanhornfeat: enable spread operator for get command rest args#18220
@mvanhornfix: clarify empty-content access diagnostics#19234
@mvanhornfix: clarify duplicate-field errors from record spreads#19352
@passionworkeerfix(dc-glob): honor negated character classes#19309
@passionworkeerfix(parser): reject command and alias names that nushell reads as numbers#19345
@passionworkeerfix(dc-glob): traverse explicit relative paths#19348
@passionworkeerfix(date): preserve offset seconds and reject malformed offsets#19434
@patatoishfix(commands): return error on invalid alignment in fill command#19361
@patatoishfix(commands): reject duplicate column names in split column#19362
@patatoishfix(commands): fix inverted error types in into int and into float#19363
@philocalystFix completion match indices, cursor edits, and IDE output#19258
@pickxchar --list: group aliases of same char, fix misalignment#19091
@pickxroundup of fixes for {hide,load,with}-env#19098
@pickxfeat(job spawn) auto-kill flag#19141
@qodeliciousWrite line breaks in to md table cells as <br>#19189
@qodeliciousfix(hide): describe the required argument as the name of what to hide#19279
@qodeliciousfix(run-external): explain a missing shebang interpreter instead of showing an internal error#19280
@qodeliciousfix(tee): keep the last help example short#19281
@qodeliciousfix(cli): show the script name instead of main in errors about a script's arguments#19282
@qodeliciousfix(into string): explain in help that binary input needs decode#19284
@qodeliciousTone down the tutor echo intro#19287
@qodeliciousfix(std/dirs): make dirs drop a no-op when only one directory is left#19355
@qodeliciousfix(to md): keep row order when rows have different columns#19356
@qodeliciousfix(update cells): return errors from the closure instead of storing them in cells#19389
@qodeliciousfix(use): keep the full directory name for module directories with a dot#19390
@rajaryan0x1fix(detect type): preserve whitespace-padded strings#19299
@rvheldenbug: debug adapter inspect deadlock#19167
@sidney3fix(into-duration): reject duplicate hh:mm:ss#19073
@sidney3fix(into-duration): into duration overflow#19075
@sidney3detect duration type#19204
@sidney3anti join#19208
@sidney3strict clocktime regex#19210
@skyfireitdiyfix: support IPv6 zone IDs in http commands#19213
@stackedbyaradhyauniq: add --keep-last, matching uniq-by#19326
@weslemCorrect float into string conversions#19166
@ymcxStart non-interactively when running as MCP server#19153
@ymcxFix IDE completion with an out of bounds location#19183
@ymcxFix crash if buffer editor is invalid#19185
@ymcxDon't allow duplicate column names in Rename#19196
@ymcxDon't let lifted columns overwrite normal columns while flattening#19201
@ymcxFix some issues with how 'into string' handles ints/floats#19265
@ymcxRename fetch_update to try_update#19267
@ymcxdisallow setting a negative indentation level in to xml#19292
@ymcxFix integer overflow with ranges#19385
Edit this page on GitHub
Contributors: Piepmatz