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 fileDefine 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-envQuoted 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]
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 memps -ladds: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]
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]
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]
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 val2Assigning $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]
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:
savechecks a customto <ext>converter's input type. A converter whose signature doesn't cover the data now errors instead of running. Built-intocommands reject the same inputs as before, but withInput type not supportedinstead of their own message.openandhttpare unchanged, since they hand converters an untyped byte stream.savekeeps a customto <ext>converter's$envchanges inside it unless it isdef --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_declchecks the input type, including empty input.'a' | example call-decl uniqnow errors withInput type not supported, andexample call-decl 'str join'withPipeline empty. view ir --jsonno longer has anastfield inir_block. It was alwaysnull.
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]
notnow has the precedencehelp operatorslists:not $a == $bmeansnot ($a == $b). Before,notapplied to the next value only. (#19271)-$xand-(expr)negate their value, also as a flag's value or an argument after--. Before,-$xwas 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.0to 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,Infinityand other spellings of special floats are strings. Useinf,nanorNaN.from nuonreads 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--helpflag are errors. (#19271) whileandloopcan't be piped, likefor. (#19271)unleterrors on constants and on$in. (#19271)- Assigning to a
mutvariable inside awherecondition is an error; the assignment never took effect. (#19271) hideinside a block (do { },if, a command body) now hides the name only in that block. (#19415)sourceof a file sourced before in a block that has ended, such asdo { 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) runkeeps a script's commands, includingmain, and its variables inside the script. Previously they stayed defined in the caller afterrun, and amainfromrunran 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 | lengthpassed|andlengthtolsas arguments. Usedeffor 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.bcreates modulea.b(commands likea.b foo) where it used to createa(a foo). The same goes for overlays, sooverlay use a.bnow gives overlaya.b. A directory namedfoo.nu/is nowfoo.nuinstead offoo. Scripts that call these commands by the short name need updating. (#19390)
Additions [toc]
Work directly with records using the new record commands [toc]
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]
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
durationName reusable types with type [toc]
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]
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]
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]
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 textRunning 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]
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]
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]
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]
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]
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 | lastFilter datetimes with older-than and newer-than [toc]
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]
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 thatexitmay kill without the "background jobs still running" warning. Jobs without the flag still trigger the warning on the firstexit, as before. (#19141)job listhas anauto_killcolumn showing which jobs carry the flag. (#19141)- Added a
--keep-last/-lflag touniq, matchinguniq-by, to keep the last occurrence of each duplicate value instead of the first. (#19326) into datetime --timezonenow accepts all timezones fromdate list-timezone. (#19139)- Added
find --only-matchingandfind -oto return only matched text, similar togrep -o. (#19150) - The language server (
nu --lsp) now reports its name and version in the LSPinitializeresponse (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-tohas a new--walk-upflag 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-upreturns../../b/c. (#19089)into durationrejects odd-length composite fields in the clock format, such as11:0:22or11:000:2(#19210)- Add
join --anti, which selects rows not present in the right table by the join column.$lhs | join --anti $rhs refis equivalent in behavior to$lhs | where ref not-in $rhs. (#19208) - On Windows, Nushell now accepts
/cand/Cas the ComSpec command switch and runs the following command line as Nushell code, improving compatibility whennu.exeis used asComSpec. This change does not affect other platforms. (#19148) - Document in
config nu --docthe$env.CMD_DURATION_MSvariable and how to use it to determine startup. (#19350) into datetime --formatslists the formatsinto datetimereads 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 as18th of April 2025, relative words such astomorrow 10am, and integer timestamps. Filter it bykind:into datetime --formats | where Kind == date. (#19413)
Performance [toc]
Faster parsing and improved parser diagnostics [toc]
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]
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 ~ | main | this PR |
|---|---|---|
| launch to first prompt | 15.70 ms | 13.10 ms |
$nu.startup-time | 8.03 ms | 7.36 ms |
| instructions retired by the first prompt | 149.3M | 119.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,updateor 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 humanizeanddate to-timezoneread 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]
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, andrejectno 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.filteris removed. Usewhere, which accepts the same closures, including closures stored in variables.- Custom completer results no longer support
positional. Usecompletion_algorithm: substringinstead. A completer returningpositional: falsenow 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]
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]
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 sqliteandstoris now 3.54.0. (#19417)
Bug fixes [toc]
Rest patterns anywhere in match lists [toc]
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" }
finishedUsing 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]
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:
| left | in right | main | this PR |
|---|---|---|---|
$.a | $.a | true | true |
$.x | $.a | true | false |
$.b.c | $.a.b.c.d | false | true |
$.0 | $.items.0 | false | true |
$.a.c | $.a.b.c | false | false |
$.a.b | $.a | false | false |
| (empty) | $.a | panic | true |
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:
> 2 | math log 1
inf
> 1 | math log 1
NaNThese calls now error, consistent with already-rejected bases such as 0:
> 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.6666666666666666Both 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]
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]
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]
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]
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]
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]
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.
> [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
╰────> [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]
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]
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]
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]
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]
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]
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:
| Command | Before | After |
|---|---|---|
try { $BIG } | str length | hangs | 300002 |
try { $BIG } catch { 'c' } | str length | hangs | 300002 |
try { $BIG | lines } | length | hangs | 1 |
try { ^yes } | lines | first 3 | hangs | [y, y, y] |
try { $OUTERR } finally {|v| print ($v | describe) } | complete | string, then Complete only works with external commands | string, then {stdout: "out\n", stderr: "err\n", exit_code: 0} |
try { $OUTERR } finally { print fin } | save -f --stderr e.txt o.txt | e.txt empty, err printed | o.txt holds out, e.txt holds err |
try { $OUTERR } catch {} finally { .. } | ignore --stderr | prints err | prints nothing on stderr |
$OUTERR o> o.txt | complete | Complete only works with external commands | {stderr: "err\n", exit_code: 0}, o.txt holds out |
$OUTERR o> o.txt | ignore | stderr dropped | err |
try { $FAILERR } catch {|e| print $'caught ($e.exit_code)' } | ignore | caught 3 | boom on stderr, caught 3 |
do { try { $FAILERR } catch {} | ignore } e> e.txt | e.txt empty | e.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:
| Command | Before | After |
|---|---|---|
try { ^sh -c 'echo hi; exit 3' | lines } | length | 0 | 1 |
try { ^sh -c 'echo hi; exit 3' } | lines | null | [hi] |
try { ^sh -c 'exit 3' } | complete | Complete only works with external commands | {stdout: "", stderr: "", exit_code: 3} |
try { ^false } | describe | nothing | byte stream |
try { ^false }; print after | after | after |
try { ^sh -c 'echo a; exit 3' | lines | each {|x| print $'side ($x)'; $x } } catch { 'caught' } | caught | side a, caught |
try { ^sh -c 'echo notnum; exit 3' | lines | each { into int } } catch {|e| $e.msg } | External command had a non-zero exit code | Can'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]
%$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]
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]
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 ++= $customMore date formats and more reliable datetime parsing [toc]
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]
infcompares as larger than every finite number, and[1.0 inf] | math maxisinf. (#19271)2.0 in 1.0..2.0istrue, and2.0 in 1.0..<2.0isfalse. (#19271)-0x10,+0b11,+5secand+1kBare numbers. (#19271)1 in [1.0]istrue. (#19271){true: 1}and[[1 2]; [3 4]]parse, with the keys"true","1"and"2". (#19271)(-9223372036854775808) mod -1is0. (#19271)if 1 { }reports the same type mismatch aswhile 1 { }, and aniforwhilecondition that fails while it runs reports its own error. (#19271)9223372036854775807nsand9223372036854775807bare exact, and integer filesize and duration literals no longer lose precision. (#19271)- A script or
nu -ccommand shows every parse warning once, not only the first. (#19271) - Clearer errors for invalid UTF-8 from
\xescapes and for unclosed raw strings. (#19271) - Reject overflow durations in
into duration(#19075) - Reject empty duration strings in
into duration(#19075) gstatno longer wraps its counts above 65,535. A repository with 70,000 untracked files used to report 4,464. (#19233)- When
gstatcan'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) gstatnow fillsignored(an ignored directory counts once) andwt_renamed. A file renamed withoutgit mvnow counts as onewt_renamedinstead of onewt_deletedplus onewt_untracked, and also aswt_modifiedif it was edited after the move. (#19233)- In a repository with no commits yet,
branchshows the branchHEADpoints to instead ofmasterorHEAD. (#19233) repo_nameis now the name of the working directory in linked worktrees and submodules (it used to beworktreesormodules) 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 installon macOS with Homebrew's libgit2. (#19233) - Pressing Ctrl-C to stop a foreground command in the REPL no longer kills background jobs from
job spawnor frozen jobs. They keep running and stay listed injob list. (#19163) - When
nu -cor a script exits, including after Ctrl-C, its background jobs are terminated instead of being left behind. Ctrl-C also terminates the jobs of anu --mcp,--lspor--dapserver. (#19163) exit <code>innu -i -c "..."ornu -i script.nunow exits with that code. Only the REPL keeps the "press exit again" warning on the firstexitwith running jobs. (#19163)exitinside 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)
hidenow hides type aliases.hide Namehides the type aliasNamewhen no alias or command has that name, andhide <module> Name,hide <module> [Name ...]andhide <module> *hide a module's exported type aliases along with its commands. (#19268)help modules <name>lists the type aliases a module exports, andscope moduleshas a newtype_aliasescolumn with each alias'sname,typeandtype_alias_id. (#19268)type lsand othertypestatements without=now explain how to write a type alias, and fortype <name>they point towhich <name>and^type <name>. (#19268)- Fixed the
--mcp-hostdescription and example innu --help. (#19268) - The MCP server's
list_commandsandcommand_helptools, and the "Did you mean" hint for an unknown command, no longer offer a command that was hidden withhidewhile another overlay was active. (#19270) command_helpnow describes the command a name actually runs when overlays shadow or hide commands. (#19270)- The MCP server's
list_commandsandcommand_helptools list an alias that passes positional arguments with only the parameters left for you to give.alias home = cd ~is listed ashome {flags}instead ofhome {flags} (path).help homeis unchanged and still shows the expansion withcd's usage. (#19270) - Match highlighting in the completion menu now lands on the right characters for non-ASCII candidates:
ßmatched byss, letters with combining accents, ligatures likeffi, 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-completenow prints valid JSON, so suggestions containing quotes or backslashes no longer produce broken output. (#19258)run script.nu ...argsrejects arguments the script'smaindoesn't accept: unknown flags, extra positional arguments, flags missing a value, and values of the wrong type.--flag=valuenow works. (#19272)rundoesn't convert values tomain's parameter types the waynu script.nudoes. Quote a number you pass to astringparameter, as inrun x.nu --name "23". (#19272)run's own flags must come before the script path. After the path,-fand--helpgo tomain. (#19272)- Flags inside a list spread now stay values, so
run x.nu ...$argsno longer passes a--fooin$argsas a flag. Use a record spread like...{foo: "23"}instead. (#19272) runcounts towardrecursion_limit, so a script that runs itself too deeply stops with an error instead of crashing nu. (#19272)- Fixed
duover-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 --longlists the first-seen link only, matching GNUdu -a. (#19283)ls --dunow counts a hard-linked file once inside each listed directory, likedudoes. (#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 aon three links to one file shows a single row forc. This matches POSIX/BSD/GNUdu, but scripts that expect one row per operand will see fewer rows. (#19283) unletworks on constants again. It hides the constant's name for the rest of the block, so a later$nameis 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 theunlet, like a completion list or a command body, keeps its value. (#19294)- Calling
unletindirectly, like%($name) $x, is now an error instead of a crash. (#19294) tableandtable --expandshrink 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, whichlsandpsalso set, now works withtable --expandand 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 --expanddraws 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_separatorthis 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,$historyindices no longer shift when old entries are evicted. An evicted index reads asnull, and$history | lengthcounts every result stored in the session. LoweringNU_MCP_HISTORY_LIMITnow trims$historyto the new limit. (#19318) nu --mcpnow runsevaluatecalls one at a time. Before, two calls sent together could get the samehistory_index, and one call's$historyentry and$envchanges were lost. (#19318)- The MCP server's instructions and tool descriptions now match nushell's behavior for
lsvsglobon hidden directories,job spawn --description,command_helpoutput, and\u{...}escapes. (#19318) - The
evaluatetool description no longer tells agents to avoid large output. Output over the limit already comes back as anotepointing at$history. (#19318) tuiwidgets 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)defaultin any$env.config.tuicolor is now the terminal's own color, andsurfaceandbackdropaccept a bare color such as"#123456". (#19375)from odsnow 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 xlsxcrashing nushell or running out of memory on a crafted file. It now reportsCould 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,minandhrnow report an error, asdayandwkalready did. (#19087) - Fixed an issue where
from nuonfailed to load a document starting with a UTF-8 byte order mark, such as one written by PowerShell'sOut-Fileor a Windows editor. (#19157) - Fixed
to nuonwriting corrupt output when--rawand--no-commaswere 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 stringfor locales and--group-digitswith floating point input. Made theinto stringrounding matchmath round. (#19166) - No crashes when
nu --ide-completeuses an out of range value like"nu --ide-complete -1 a.nu"(#19183) - Fixed
to nuon --prettypadding 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.VISUALor$env.EDITORnames an editor that can't be found; the keypress now does nothing. (#19185) - Fixed
to mdproducing 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 --clearwith 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 stringwith a very large-dvalue no longer panics; it returns the unrounded value. (#19191)- Fixed
std/dtdatetime-diffreturning a negative or incorrectdayvalue when the earlier date is at the end of a month (for example Jan 31 → Mar 1). (#19109) - Fixed
to nuonwriting a raw NUL byte into its output; a NUL is now escaped as\0and forces quoting, so the output round-trips. (#19161) - Fixed an issue where
bytes remove --endsilently dropped leading bytes (or the whole input) when the pattern was not present in the input.--endremoves the last occurrence anywhere in the input, not only a suffix. (#19107) - Fixed
whoamiloading translations for the wrong command, which could make its error messages show up untranslated. (#19144) - Fixed an issue where aliasing
metadatawould break its use instd(#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)
openandsaveno 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 asalias "from jsonc" = from json. They now explain that the converter must be a command and suggest the matchingdef, for exampledef 'from jsonc' [] { from json }. (#19205)first --strictandlast --stricton an empty list, stream or binary now reportnu::shell::access_empty_content("Cannot access empty content.") instead of a misleading "Row number too large" error. (#19234)tutor conditionaldescription text no longer has wording typos. (#19218)- Fixed
std/helpexternal 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, withAlias for `...`as its description. Afteralias st = str trim,help strshowsst (alias) - Alias for `str trim`belowstr trim, where it used to show a secondstr trimline. A hidden alias is no longer listed, and a script'salias "main baz" = main barnow appears inscript.nu --helpasscript.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'salias mb = main barnow appears inscript.nu --help, right afterscript.nu bar. (#19261)- The MCP server's
list_commandsandcommand_helptools now name each command the way you call it. An alias such asalias st = str trimis listed asstinstead of as a secondstr trim,command_help stworks, and defining the alias no longer replacesstr trim's help with the alias's. Module commands are listed under the nameusegives them, such asspam foo barafteruse spam. (#19262) help hidenow 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 teeexample now prints 100 lines instead of 10000. (#19281) help into stringnow explains thatinto stringdoes not convert binary data: binary input returns an error that points todecode, for example0x[68 69] | decode utf-8. The error hint for binary input is also clearer. (#19284)- The
tutor echointro is now more accurate and mentions that a plain value works the same as passing it toecho. (#19287) - Fixed a crash when
chunksis given a chunk size too large to allocate, such as 9223372036854775807. (#19286) to xmlnow disallows setting a negative indentation amount. (#19292)- Fixed a crash when
lastis 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 ofmain, when the script name parses as a command. Other names (for example10kborit's.nu) still showmain. (#19282) - Fixed a crash when
windowis given a window size too large to allocate, such as 9223372036854775807. (#19288) - Fixed a crash when
table --abbreviatedis given a row count too large to allocate, such as 9223372036854775807. (#19296) - Previously, the
version checkcommand 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_TOKENorGH_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 leftorroll righton an empty list or record. (#19285) - Fixed an issue where
printhid the failure of an external command: a failing external command piped intoprintnow 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 | printwith no match now errors, anddo -i { ^false } | printnow fails likedo -i { ^false } | collectalready 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:folderand just typingd:(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 withf. (#19309) - Fixed Tab replacing a partly typed subcommand with a file name, such as
git re<Tab>becominggit README.mdin a directory that has aREADME.md. (#19344) - Fixed
dirs dropchanging 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 intandinto floatconversion 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 columnnow rejects duplicate column names with acolumn_defined_twiceerror pointing at both uses, instead of silently overwriting the earlier column. (#19362)fill --alignmentnow errors on an unknown alignment instead of silently left-aligning; valid values areleft,right,center/middleandcenterright/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
letwithout a type annotation gets a list from chainedupdatecalls 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. Forlet a = {s: 1}; {...$a, s: 3}, the error underliness: 3as the redefinition and...$aas whereswas 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 suggestmergeorupdateto replace a field. (#19352) - Fixed
update cellshiding errors from its closure. An error inside the closure is now raised instead of being stored as the cell value. (#19389) rmno longer removes hidden files through a glob, at any depth, unless the pattern starts a name with.or--allis given. Before,rm **/*.txtalso removed.txtfiles inside hidden directories, and with thedc-globexperimental optionrm *removed dotfiles. (#19421)gridnow 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-timezonepreserves seconds in numeric offsets such as+05:30:15and rejects invalid suffixes and separators such as+05:30XYZ,+05:, and+05:::30. Historical time zones with second-level offsets round correctly withdate flooranddate 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::CtrlCis nowSignal::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 toSignal::CtrlC(buffer)orSignal::CtrlC(_). (#1290) - Breaking:
HistoryTimestampreplaceschronotypes in the public history API. Usefrom_millis,to_millis, ornow; serializedHistoryItem::start_timestampvalues are integer milliseconds rather than RFC 3339 strings.DefaultPromptSegment::CurrentDateTimeis replaced byDynamic(fn() -> String), and the default right prompt is now empty. (#1248) - Exhaustive event matches need
FirstHistoryandLeaveHistory; exhaustive edit-command matches needCapitalizeWord.MoveWordRightEndis deprecated in favor ofMoveWordRight. (#1281, #1280, #1292) with_status_line(Box<dyn StatusLine>)adds text below the buffer and hints. Custom menus should account forPainter::remaining_linesandremaining_lines_realexcluding the reserved status rows. (#1268)- The external printer no longer requires a feature flag.
with_external_printeraccepts anyExternalOutput; the oldexternal_printerfeature 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)
EditorCommandexposes buffer-editor template rendering,EventStatusis exported for custom edit modes, andMenugains defaultselection_atandset_selectionmethods 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::GenericErrorwithShellError::Generic(GenericError). - Replace
PipelineData::metadata()withmetadata_ref(),metadata_mut(), ortake_metadata(). - Replace
EngineState::current_work_dir()andStateWorkingSet::get_cwd()withEngineState::cwd()orcwd_as_string(). - Replace
ast::Call::positional_nth()andpositional_len()withpositional_iter(). - The unused
ShellError::DeprecationWarningis 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! 🙏
| author | change | link |
|---|---|---|
| @cptpiepmatz | Update CI artifact uploading | #19106 |
| @fdncred | Impl Hash for Value and inner types in nu-protocol | #18933 |
| @hustcer | Preserve warnings in nightly release builds | #19232 |
| @fdncred | Drop the shared short flag that #19271 made a parse error | #19274 |
| @ayax79 | Fix polars test breakages | #19317 |
| @ayax79 | Added the local_socket feature for nu-plugin-test-support for formats… | #19319 |
Full changelog [toc]
| author | title | link |
|---|---|---|
| @4RH1T3CT0R7 | Reject command names with irregular whitespace at definition time | #18969 |
| @Adnan-Husayn | feat(lsp): report serverInfo in the initialize response | #19180 |
| @GhostCoder6969 | Fix it-if typo in chained error doc comment | #19143 |
| @Huang-404-Q | fix(nu-term-grid): accept a grid that is exactly as wide as the limit | #19409 |
| @Kissaki | Fix conditional tutor text typos | #19218 |
| @Master-Norna | fix(bytes remove): keep input unchanged when --end pattern is not found | #19107 |
| @Master-Norna | fix(math variance): use a numerically stable two-pass formula for numbers | #19108 |
| @Master-Norna | fix(std/dt): compute the day remainder directly in datetime-diff | #19109 |
| @Master-Norna | fix(math log): reject invalid bases and a NaN input value | #19127 |
| @Monster-GM | fix: report missing closure blocks instead of panicking | #19159 |
| @Sha1rholder | Remove x86_64-darwin target in flake.nix | #19173 |
| @Shub3am | Take update cells columns as rest arguments and deprecate --columns | #19125 |
| @SyedYousufFaizan | Fix(LSP) lsp crash on symbol requests for unopened or closed documents | #19194 |
| @Tyarel8 | fix(version check): propagate error and use github token | #19298 |
| @Tyarel8 | feat(docs): document $env.cmd_duration_ms and how to check for startup with it | #19350 |
| @Tyarel8 | feat: make first and last const | #19399 |
| @aakarshitv | Use whoami's own uucore locale in the whoami command | #19144 |
| @akasakariko | Preserve REPL background jobs on Ctrl-C and clean up jobs on non-REPL exit | #19163 |
| @akasakariko | Reset stale REPL interrupts before running a new command | #19337 |
| @akshitj11 | fix(cli): accept /c as commands flag | #19148 |
| @akshitj11 | fix(std/help): preserve external help arguments | #19149 |
| @akshitj11 | feat(find): add only matching output flag | #19150 |
| @app/dependabot | build(deps): bump similar from 3.1.0 to 3.2.0 | #18905 |
| @app/dependabot | build(deps): bump xxhash-rust from 0.8.15 to 0.8.19 | #19155 |
| @app/dependabot | build(deps): bump taiki-e/install-action from 2.87.21 to 2.87.24 | #19177 |
| @app/dependabot | build(deps): bump hustcer/setup-nu from 3.27 to 3.28 | #19178 |
| @app/dependabot | build(deps): bump uuid from 1.26.0 to 1.27.0 | #19179 |
| @app/dependabot | build(deps): bump unicase from 2.9.0 to 2.10.0 | #19240 |
| @app/dependabot | build(deps): bump lean_string from 0.7.0 to 0.8.0 | #19241 |
| @app/dependabot | build(deps): bump actions/upload-artifact from 7.0.1 to 7.0.2 | #19242 |
| @app/dependabot | build(deps): bump taiki-e/install-action from 2.87.24 to 2.87.27 | #19243 |
| @app/dependabot | build(deps): bump vedantmgoyal2009/winget-releaser from 4ffc7888bffd451b357355dc214d43bb9f23917e to b7370d4d152efdce803a26cc6ca9eee58cb2ad54 | #19244 |
| @app/dependabot | build(deps): bump uuid from 1.27.0 to 1.28.0 | #19245 |
| @app/dependabot | build(deps): bump crate-ci/typos from 1.50.3 to 1.51.1 | #19246 |
| @app/dependabot | build(deps): bump taiki-e/install-action from 2.87.27 to 2.87.29 | #19304 |
| @app/dependabot | build(deps): bump tango-bench from 0.8.0 to 0.9.0 | #19305 |
| @app/dependabot | build(deps): bump serde-saphyr from 1.3.0 to 2.0.0 | #19306 |
| @app/dependabot | build(deps): bump arboard from 3.6.1 to 3.7.0 | #19307 |
| @app/dependabot | build(deps): bump hustcer/setup-nu from 3.28 to 3.29 | #19364 |
| @app/dependabot | build(deps): bump taiki-e/install-action from 2.87.29 to 2.87.31 | #19365 |
| @app/dependabot | build(deps): bump actions/setup-python from 7.0.0 to 7.1.0 | #19366 |
| @app/dependabot | build(deps): bump Swatinem/rust-cache from 2.9.2 to 2.9.3 | #19367 |
| @app/dependabot | build(deps): bump uuid from 1.28.0 to 1.29.0 | #19368 |
| @app/dependabot | build(deps): bump fancy-regex from 0.19.0 to 0.20.0 | #19370 |
| @app/dependabot | build(deps): bump taiki-e/install-action from 2.87.31 to 2.89.0 | #19425 |
| @app/dependabot | build(deps): bump rstest from 0.27.0 to 0.28.0 | #19426 |
| @app/dependabot | build(deps): bump brotli from 9.0.0 to 9.1.1 | #19427 |
| @app/dependabot | build(deps): bump aws-config from 1.12.0 to 1.13.0 | #19429 |
| @app/dependabot | build(deps): bump mq-markdown from 0.9.2 to 0.10.0 | #19430 |
| @armadavalor | fix(cd): resolve Windows drive-relative paths like d: the way cmd does | #19332 |
| @armadavalor | fix: don't rewrite path separators for external args that merely contain ... | #19333 |
| @ayax79 | MCP: Added allowed-hosts and allowed-origins flags | #19076 |
| @ayax79 | Allow Custom Types to be used in type signatures | #19311 |
| @ayax79 | Fix polars test breakages | #19317 |
| @ayax79 | Added the local_socket feature for nu-plugin-test-support for formats… | #19319 |
| @bercedev | fix(try): drain a piped stderr before collecting an external | #19339 |
| @bfren | Optimize module reloading check | #19228 |
| @carlos-mercado | docs: add record, table, and list-of-strings examples to str substring | #19354 |
| @cptpiepmatz | Update CI artifact uploading | #19106 |
| @cptpiepmatz | Allow TZ_VARIANTS in into datetime --timezone | #19139 |
| @cptpiepmatz | Prep patch release | #19154 |
| @cptpiepmatz | After patch release | #19156 |
| @draconacht | update eml-parser version to 0.1.6 | #19257 |
| @eugenesvk | Use builtin command sigil to avoid bugs when user aliases shadow builtin | #19224 |
| @fdncred | group-by --to-table keep original types | #18853 |
| @fdncred | impl Hash for Value and inner types in nu-protocol | #18933 |
| @fdncred | perf(parser): parse real scripts about 1.3x faster | #19138 |
| @fdncred | fix(ps): list every process and report the same columns on every platform | #19145 |
| @fdncred | bmp rust toolchain to 1.97.1 | #19160 |
| @fdncred | minor updates to AGENTS.md and CONTRIBUTING.md | #19164 |
| @fdncred | fix(match): allow .. and ..$rest anywhere in a match list pattern, like Rust | #19172 |
| @fdncred | fix(cell-path):in and not-in between cell paths, and a panic on an empty cell path | #19187 |
| @fdncred | record family of commands | #19190 |
| @fdncred | fix(table): stop table --expand hanging when a nested table is wider than its column | #19212 |
| @fdncred | fix(join): error when a table has no rows with the join column | #19219 |
| @fdncred | fix(tui): error when a closure has no table, tree, or select to follow | #19220 |
| @fdncred | Add type aliases with a type keyword | #19223 |
| @fdncred | fix: count closure calls toward recursion_limit so infinite closure recursion errors instead of crashing | #19229 |
| @fdncred | fix(gstat): stop wrapping counts and reporting unreadable status as clean, fill ignored and wt_renamed, link libgit2 statically | #19233 |
| @fdncred | Bump locked dependencies to clear the RustSec audit | #19235 |
| @fdncred | Faster startup: chained fixups on Apple silicon, a cheaper banner, and async prompt pushes that survive | #19236 |
| @fdncred | fix(parser): try string last in oneof so oneof<string, list<string>> parses [a b] as a list | #19238 |
| @fdncred | Bump rustls to 0.23.46 to clear the RustSec audit | #19249 |
| @fdncred | fix(parser): treat a bare word after and/or/xor in a row condition as a column | #19251 |
| @fdncred | fix(each): report the closure's error instead of "Eval block failed with pipeline input" | #19252 |
| @fdncred | fix(help): list an alias in a command's subcommands under its own name | #19253 |
| @fdncred | Let metadata <expr> and stor insert/update record flags ignore pipeline input instead of erroring | #19254 |
| @fdncred | fix(help): drop hidden subcommands and fix multi-line, backticked, and script alias entries | #19261 |
| @fdncred | fix(mcp): list and look up commands by the name they're called by | #19262 |
| @fdncred | fix(cli): correct the --mcp-host help text and example | #19268 |
| @fdncred | fix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes | #19270 |
| @fdncred | Fix the bugs found by the nu-conformance open questions | #19271 |
| @fdncred | fix(run): reject script arguments that main doesn't accept | #19272 |
| @fdncred | Ignore the zip extraction advisories in cargo audit, since calamine never extracts | #19273 |
| @fdncred | test(run): drop the shared short flag that #19271 made a parse error | #19274 |
| @fdncred | fix(unlet): hide a constant's name instead of rejecting it | #19294 |
| @fdncred | fix(table): shrink the widest columns first and honor width priorities everywhere | #19303 |
| @fdncred | Bump webpki crates to clear the RustSec audit | #19308 |
| @fdncred | Add extern --strict to reject undeclared flags | #19313 |
| @fdncred | Add generate completions to auto-generate extern definitions, with completions, from carapace, zsh, fish, man pages and --help | #19314 |
| @fdncred | Add @structured attribute so an extern can return data | #19316 |
| @fdncred | fix(nu-mcp): keep $history indices stable, run evaluations one at a time, and correct stale guidance in the MCP instructions and AGENTS.md | #19318 |
| @fdncred | Remove file accidentally committed | #19331 |
| @fdncred | Shorter table escape sequences, and a new ansi opt command | #19340 |
| @fdncred | Don't let Tab's partial completion drop suggestions that replace a different span | #19344 |
| @fdncred | Fix try hanging under pipefail, and keep an external's stderr through finally and o> | #19349 |
| @fdncred | Run commands found by id through one IR call path (AST migration phase 3) | #19351 |
| @fdncred | Bump webpage and zstd-sys, ignore the other zstd advisories to clear the RustSec audit | #19359 |
| @fdncred | bump scraper to 0.29.0, lru to 0.19.0, calamine to 0.37.0 | #19373 |
| @fdncred | fix(tui): draw on the terminal's own background by default | #19375 |
| @fdncred | Keep list<any> in the inferred output of update on a union with a custom type | #19379 |
| @fdncred | Bump libz-sys to 1.1.31 to clear RUSTSEC-2026-0418 | #19381 |
| @fdncred | Remove deprecations older than six months | #19382 |
| @fdncred | Add from dotenv and to dotenv, and have load-env and with-env convert what they set | #19391 |
| @fdncred | Make closures that call commands faster, and into datetime on RFC 3339 strings | #19394 |
| @fdncred | Add older-than and newer-than operators for datetimes | #19397 |
| @fdncred | Replace dtparse with a jiff-based date reader | #19398 |
| @fdncred | A status line under the prompt: errors, signatures, types and const previews as you type | #19403 |
| @fdncred | Pass flags through %$cmd dynamic builtin dispatch | #19404 |
| @fdncred | Update ci.yml with incredibuild-macos-latest | #19405 |
| @fdncred | Update Cargo.toml for __eh_frame section warning | #19412 |
| @fdncred | Add into datetime --formats to list the formats it reads | #19413 |
| @fdncred | math sum size and the other math reducers sum a table's column | #19414 |
| @fdncred | Fix the nu-conformance open questions A1, P1, H1 and R1, and two source bugs | #19415 |
| @fdncred | Bump calamine to 0.38.0 to clear the RustSec audit | #19420 |
| @fdncred | rm never lets a glob match a hidden file unless asked | #19421 |
| @fdncred | dc-glob follows nu-glob's rules in every command, with {a,b} added | #19422 |
| @fdncred | table --collapse lines up rows and stays within --width | #19424 |
| @feiiiiii5 | fix(nuon): error on a duration head that overflows | #19087 |
| @feiiiiii5 | Strip one leading byte order mark in from nuon | #19157 |
| @feiiiiii5 | Reject to nuon --raw --no-commas, which writes no separator | #19158 |
| @feiiiiii5 | Escape NUL as \\0 in nuon output instead of writing a raw byte | #19161 |
| @feiiiiii5 | Measure nuon table column widths in runes, not bytes | #19165 |
| @gleb-chipiga | Release plugin inputs on response completion or output drop | #19171 |
| @hexbinoct | Report SQLite errors from query db | #19377 |
| @hsdfat | Clear sqlite history with SQL instead of deleting the file | #19092 |
| @hustcer | fix(ci): preserve warnings in nightly release builds | #19232 |
| @intertermux-code | fix(du): count a hard-linked file once, not once per link | #19283 |
| @itsF4LCON | open/save: give a clear error suggesting def when the from/to converter is an alias | #19205 |
| @jaeminbird | Strip one leading byte order mark in from json | #19383 |
| @jaideeppyne | test(parser): pin exact whole-number unit literals and scaled overflow | #18898 |
| @kronberger-droid | test(config): compare canonical paths in test_default_config_path | #19044 |
| @kronberger-droid | chore: bump reedline to e9fcfdb | #19175 |
| @kronberger-droid | fix(nix): take libx11 instead of the deprecated xorg set | #19181 |
| @kronberger-droid | chore: bump reedline to d704744 | #19202 |
| @kronberger-droid | chore: bump reedline to 39db5e3 | #19290 |
| @kronberger-droid | chore: bump reedline to c8d81b2 | #19342 |
| @kronberger-droid | chore: bump ctutils, tokio and clipboard-win to clear the RustSec audit | #19343 |
| @kronberger-droid | chore: bump reedline to 4a3dad3 | #19401 |
| @kronberger-droid | chore(reedline): bump reedline to 8bc5cd0 | #19416 |
| @kronberger-droid | chore(deps): bump rusqlite to 0.41.1 and reedline to 4fcf4fb | #19417 |
| @kronberger-droid | fix(config)!: make assigning keybindings and menus replace the list | #19418 |
| @kronberger-droid | fix(config): reject a keybindings or menus list with an entry it can't read | #19438 |
| @latent-9 | fix: reject out-of-range decimals in into string | #19191 |
| @manish-9245 | fix(print): surface external failures instead of masking exit code (#19227) | #19260 |
| @manoj-1407 | Fix roll panic on empty lists and records | #19285 |
| @manoj-1407 | Fix chunks crash when the chunk size is too large to allocate | #19286 |
| @manoj-1407 | Fix window crash when the window size is too large to allocate | #19288 |
| @manoj-1407 | Fix last crash when the count is too large to allocate | #19295 |
| @manoj-1407 | Fix table --abbreviated crash when the row count is too large to allocate | #19296 |
| @maxim-uvarov | Path relative to walkup | #19089 |
| @mirsella | Fix OSC 7 directory URL escaping | #19358 |
| @mvanhorn | feat: enable spread operator for get command rest args | #18220 |
| @mvanhorn | fix: clarify empty-content access diagnostics | #19234 |
| @mvanhorn | fix: clarify duplicate-field errors from record spreads | #19352 |
| @passionworkeer | fix(dc-glob): honor negated character classes | #19309 |
| @passionworkeer | fix(parser): reject command and alias names that nushell reads as numbers | #19345 |
| @passionworkeer | fix(dc-glob): traverse explicit relative paths | #19348 |
| @passionworkeer | fix(date): preserve offset seconds and reject malformed offsets | #19434 |
| @patatoish | fix(commands): return error on invalid alignment in fill command | #19361 |
| @patatoish | fix(commands): reject duplicate column names in split column | #19362 |
| @patatoish | fix(commands): fix inverted error types in into int and into float | #19363 |
| @philocalyst | Fix completion match indices, cursor edits, and IDE output | #19258 |
| @pickx | char --list: group aliases of same char, fix misalignment | #19091 |
| @pickx | roundup of fixes for {hide,load,with}-env | #19098 |
| @pickx | feat(job spawn) auto-kill flag | #19141 |
| @qodelicious | Write line breaks in to md table cells as <br> | #19189 |
| @qodelicious | fix(hide): describe the required argument as the name of what to hide | #19279 |
| @qodelicious | fix(run-external): explain a missing shebang interpreter instead of showing an internal error | #19280 |
| @qodelicious | fix(tee): keep the last help example short | #19281 |
| @qodelicious | fix(cli): show the script name instead of main in errors about a script's arguments | #19282 |
| @qodelicious | fix(into string): explain in help that binary input needs decode | #19284 |
| @qodelicious | Tone down the tutor echo intro | #19287 |
| @qodelicious | fix(std/dirs): make dirs drop a no-op when only one directory is left | #19355 |
| @qodelicious | fix(to md): keep row order when rows have different columns | #19356 |
| @qodelicious | fix(update cells): return errors from the closure instead of storing them in cells | #19389 |
| @qodelicious | fix(use): keep the full directory name for module directories with a dot | #19390 |
| @rajaryan0x1 | fix(detect type): preserve whitespace-padded strings | #19299 |
| @rvhelden | bug: debug adapter inspect deadlock | #19167 |
| @sidney3 | fix(into-duration): reject duplicate hh:mm:ss | #19073 |
| @sidney3 | fix(into-duration): into duration overflow | #19075 |
| @sidney3 | detect duration type | #19204 |
| @sidney3 | anti join | #19208 |
| @sidney3 | strict clocktime regex | #19210 |
| @skyfireitdiy | fix: support IPv6 zone IDs in http commands | #19213 |
| @stackedbyaradhya | uniq: add --keep-last, matching uniq-by | #19326 |
| @weslem | Correct float into string conversions | #19166 |
| @ymcx | Start non-interactively when running as MCP server | #19153 |
| @ymcx | Fix IDE completion with an out of bounds location | #19183 |
| @ymcx | Fix crash if buffer editor is invalid | #19185 |
| @ymcx | Don't allow duplicate column names in Rename | #19196 |
| @ymcx | Don't let lifted columns overwrite normal columns while flattening | #19201 |
| @ymcx | Fix some issues with how 'into string' handles ints/floats | #19265 |
| @ymcx | Rename fetch_update to try_update | #19267 |
| @ymcx | disallow setting a negative indentation level in to xml | #19292 |
| @ymcx | Fix integer overflow with ranges | #19385 |