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

Nushell 0.116.0

Today, we're releasing version 0.116.0 of Nu. This release brings a major custom completion rework, new tui commands for building terminal interfaces, interactive debugging, more tutor lessons, and a faster shell.

In memory of Yash

"It is with profound grief
and deep love
that the family of
Yash Thakur
announces his passing on
April 2, 2026."

The Nushell team is deeply saddened by Yash's passing.

We found out about his passing recently and wanted to acknowledge his dedication and contributions to our project, as well as the friendship he shared with the Nushell community. Our condolences go out to his friends and family.

Yash started working on Nushell at the young age of 19 in September 2023.

He quickly learned the project and, in a short time, became a valuable contributor to the inner workings of Reedline, the parser, completions, and other components. At the time of his passing, he was also helping develop a new parser for Nushell.

Please consider reading the beautiful obituary written for Yash to learn more about his life, passions, interests, and amazing spirit.

  • Yash Santosh Thakur Obituary

Where to get it

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

I'm too lazy to type, lemme press tab [toc]

Pressing Tab is easy. Making everything behind it agree on how completions work took a bit more effort. Thanks to @philocalyst, custom completions now share one input and output model across parameter completers, command-wide completers, external completers, and menu sources. Completers can ask for the token, the completion location, or the whole buffer, and combine their suggestions with other completion sources.

Breaking change

Existing custom completers and menu sources may need updating. See the examples and migration table in unified custom completions.

There are plenty of smaller improvements around that big rework, too. Completers can now see which command you are completing, and external completers receive expanded aliases. Sourced menus refresh properly after partial completion, warnings wait until the menu closes, and you can opt into keeping completion and history menus open while editing. Less fighting the menu, more pressing Tab.

Teach me things [toc]

Nushell's interactive tutor has more lessons for you. Thanks to @nos1dot618, you can now learn about command-history shortcuts and $env, write your own custom commands and work with pipeline input, and get to grips with if, match, and where.

If you have been meaning to move beyond the commands you already know, this is a good excuse. Run tutor and try a lesson right there in your shell.

Build your TUI straight in Nushell [toc]

Ever wanted your script to have a little interface? Thanks to @fdncred, the new tui commands let you build interactive terminal interfaces straight from Nushell. Put together tables, textboxes, menus, and more, then get the user's selections and entered values back as a record.

You probably won't replace your entire Ratatui application this afternoon, but a picker or a small form no longer needs a separate Rust project. You can even open it as a floating dialog, and your shell comes back intact when you quit. Take a look at the commands and examples here, then head over to the original PR for more. Even this changelog cannot easily cover everything these commands can do.

Interactive debugging! [toc]

That script is doing something strange again. Time to set a breakpoint. Thanks to @rvhelden, Nushell now has a Debug Adapter Protocol server, started with nu --dap, so you can debug your scripts from an editor that supports DAP.

Set breakpoints, step through pipelines, inspect variables, and evaluate watch expressions. You can even step backward through a recorded timeline when you realize you just stepped past the interesting bit. A lot of work behind a small flag. More details are here.

Make Nushell faster [toc]

There is less waiting around this release, too. Typing and completing use in the REPL does less work, and large configs load faster, along with the plugin registry. gstat also finds the nearest tag faster in large repositories.

$nu.startup-time now measures all the way to the first prompt being ready, so you get a more honest account of where that time went. There is also faster parsing and less work when styling values, and the repeated source slowdown introduced in 0.115 is fixed. Thanks to everyone making the shell a little quicker, one less bit of unnecessary work at a time.

Changes [toc]

Breaking changes [toc]

Unified custom completions [toc]

PR #18791 by @philocalyst

Custom completions now use one shared input and output model across parameter completers, command-wide completers, external completers, and menu sources. This makes completion behavior more consistent, but it means existing custom completers and menu sources may need to be updated.

Previously, different completion entry points received different arguments. Parameter completers received something like [context, offset], command-wide completers received [spans], external completers commonly received {|spans| ...}, and menu sources received {|buffer, position| ...}.

Completers now declare which completion inputs they want by naming their positional parameters. The recognized names are token, place, and buffer, and they can be declared in any order.

def complete-branch [token: record] {
    git branch --format '%(refname:short)' | lines | where $it =~ $token.text
}

def complete-from-place [place: record] {
    if $place.kind == "flag-value" and $place.flag == "profile" {
        [debug release]
    }
}

def complete-from-buffer [buffer: string] {
    $buffer | split row " "
}

token describes the token at the cursor, with fields like text, kind, and span. place describes the resolved completion site and replacement range, including fields like cursor, target, kind, flag, index, and shape when applicable. buffer is the exact command line from the beginning of the line through the cursor, including text before pipes, inside closures, and after separators.

Use buffer instead of calling commandline from inside a completer. buffer is always the line currently being completed; commandline can be empty in some editor states, such as after ;.

Menu sources use this same input model now. A source that used to look like this:

source: {|buffer, position|
    $buffer | str substring ..<$position | split row " " | last
}

should usually become either:

source: {|token| $token.text }

or, if it really needs the whole line:

source: {|buffer| $buffer }

External completers also need to migrate from the old spans-style input to the new named inputs. For example, a whole-line external completer should declare buffer:

$env.config.completions.external.completer = {|buffer|
    let words = $buffer | split row " "
    carapace ($words | first) nushell ...$words | from json
}

If a completer declares an unrecognized positional name, Nushell passes nothing for that parameter and writes a diagnostic to the completion log.

Custom completer output is also handled more consistently. A completer can now return null to decline and let another completion source answer, a string or list of strings, suggestion records, or an envelope record with completions, options, and fallback.

def complete-preset [token: record] {
    {
        completions: [
            {value: main, description: "default branch"}
            {value: release, description: "release branch"}
        ]
        options: {
            filter: true
            completion_algorithm: "substring"
            match_description: true
        }
        fallback: true
    }
}

fallback: true keeps the custom results and continues to the next completion source, so custom completions can appear beside built-in file completion or command-wide completions. Parameter completers are filtered by default; command-wide and external completers are not, because they usually do their own filtering. Set options.filter explicitly if you need the other behavior.

The old global background-completions option has been removed. Completers normally run on a background worker. If a completer needs to own the terminal, such as one that launches fzf or input list, mark the completer command with @interactive:

@interactive
def pick-file [token: record] {
    ls | get name | to text | ^fzf --query $token.text | lines
}

def open-file [path: string@pick-file] {
    open $path
}

When completing open-file <Tab>, pick-file runs inline on the line-editor thread with stdin and the terminal available. This blocks the editor while the picker is open, then returns the selected values as completion suggestions. Calling an @interactive completer directly is not the intended test path, because the completion engine supplies its inputs.

External completers are closures and cannot carry @interactive themselves. To make an external completer interactive, have the closure call an @interactive command:

@interactive
def carapace-fzf [buffer: string] {
    let words = $buffer | split row " "
    carapace ($words | first) nushell ...$words | from json | ^fzf | lines
}

$env.config.completions.external.completer = {|buffer|
    carapace-fzf $buffer
}

commandline complete gained tools for developing completers. commandline complete --input returns the {token, place, buffer} record a completer would receive without running the completer. commandline complete --detailed returns suggestions in the custom-completer output format. commandline complete --type directory|path|glob|command|variable|env-var runs one built-in completion source, which is useful when composing Nushell's built-in completions with custom ones. --input cannot be combined with --detailed or --type.

Some completion behavior changed as part of this unification:

  • Parameter completers that fail now return no suggestions instead of unexpectedly falling back to the working directory.
  • Command-wide and external completers can return null to decline, allowing file completion or another source to answer.
  • Completion state is resolved at the cursor more accurately, including nested closures, aliases, multi-word command heads, flag values, cell paths, and empty argument slots.
  • Aliases resolve through to their completion command, including whether that command is interactive.
  • Malformed suggestions, styles, spans, or options are reported in the completion log without discarding unrelated valid suggestions.

Common migrations:

Previous formNew form
def comp [input pos] { ... }def comp [token: record] { $token.text | ... }
def comp [spans] { ... }def comp [buffer: string] { $buffer | split row " " | ... } when whole-line input is needed
{ |spans| ... } external completer{ |buffer: string| ... }
{ |buffer position| ... } menu source{ |token: record| ... }, { |place: record| ... }, or { |buffer: string| ... }
Global background-completion opt-out@interactive on the terminal-owning completion command

Other breaking changes

  • Replaced to yaml/to yml's --compact-list-indent flag with --list-indent flag which takes either compact or indented. (#19005)

Additions [toc]

Named flags: null can omit or pass through based on type [toc]

PR #18796 by @fdncred

When a named flag is given null, Nushell now:

  • Omits the flag if its type does not accept nothing (e.g. --x: int, --preserve: list<string>), so defaults and “flag not passed” behavior work—especially useful when shadowing builtins with %cp / %ls and writing --flag=$maybe_null
  • Passes null through if the type accepts nothing (e.g. --x: any, --x: oneof<int, nothing>), so callers can still express an explicit null when they opt into that in the signature
def f [--x: oneof<int, nothing> = 5] { $x }
f            # 5
f --x=null   # null

def g [--x: int = 5] { $x }
g --x=(null)   # 5 (omitted → default) note: in this example null is wrapped in parens because this syntax would fail with `g --x=null` as you're typing due to parse checking.

Record spread into named flags [toc]

PR #18796 by @fdncred

Internal and custom commands accept spreading a record as named flags:

def wrap [--preserve: list<string>, --recursive, ...rest] {
  %cp ...{ preserve: $preserve, recursive: $recursive } ...$rest
}

let flags = {preserve: [mode], recursive: true}
wrap ...$flags src dest

Null fields follow the same type rule as named flags above. For switch fields, true sets the flag, while false or null omits it. Field values are type-checked against the flag signature, and unknown flag names in the record cause a runtime error. Spreading a list into a command with no ...rest produces a clear error, since lists are not treated as named flags.

New Polars commands can create date and datetime ranges [toc]

PR #18887 by @ayax79

Implemented commands for creating date and datetime ranges:

CommandDescription
polars date-rangeCreate a date range expression.
polars date-rangesCreate a column of date ranges.
polars datetime-rangeCreate a datetime range expression.
polars datetime-rangesCreate a column of datetime ranges.

The interactive tutor now teaches command-history shortcuts and the $env variable [toc]

PR #18903 by @nos1dot618

Added a tutor shortcuts tutorial covering command history shortcuts.

> tutor shortcut

You can use shortcuts to quickly insert text from command history into the
input buffer.

You can use !! to insert the last command you entered into the input buffer.

!!

After pressing Enter, !! is expanded into the previous command in the input
buffer. The expanded command is not executed until you press Enter again.

You can also use !! as part of a larger command.

tutor shortcut
!! | find "shortcut"

The above expands !! into the previous command while keeping the rest of the
text in the input buffer.

You can use !$ to insert the last spatially delimited argument from the
previous command into the input buffer.

echo hello world
echo !$

After pressing Enter, !$ is expanded to world in the input buffer. The
resulting command is not executed until you press Enter again.

You can use !<idx> to insert a command from the command history into the input
buffer. The index corresponds to the command's index in the history.

history
!5

After pressing Enter, !5 is expanded to the command with history index 5 in
the input buffer.

You can use !-<number> to insert a command from a number of entries back in
the history into the input buffer.

!-5

After pressing Enter, !-5 is expanded to the command from five entries back in
the history.

The variable tutorial now also documents the $env built-in variable.

> tutor variable

Variables are an important way to store values to be used later. To create a
variable, you can use the let keyword. The let command will create a
variable and then assign it a value in one step.

let x = 3

Once created, we can refer to this variable by name.

$x

Nushell also comes with built-in variables. The $nu variable is a reserved
variable that contains a lot of information about the currently running
instance of Nushell. The $env variable contains the environment variables
available to the current Nushell process. The $it variable is the name given
to row-condition closure parameters if you don't specify one. And $in is the
variable that allows you to work with all of the data coming in from the
pipeline in one place.

The interactive tutor now covers custom commands and pipeline input [toc]

PR #18927 by @nos1dot618

Added new tutor tutorials for defining custom commands and working with pipeline input.

> tutor custom-command

Custom commands allow you to create your own commands in Nushell. You can
define a custom command using the def keyword.

For example, this defines a command called greet:

def greet [] {
    print "Hello!"
}


You can then run it just like any other command:

greet


Custom commands can also accept arguments. You define the arguments between
the square brackets:

def greet [name] {
    print $"Hello, ($name)!"
}


Now you can pass a name to the command:

greet "Nushell"


You can give arguments a type to make the expected input clearer:

def add [a: int, b: int] {
    $a + $b
}


You can also provide default values for arguments:

def greet [name = "world"] {
    print $"Hello, ($name)!"
}


You can learn more about using pipeline input with custom commands by running:

tutor pipeline-input


You can learn more about custom commands and see additional examples by
running:

help def


> tutor pipeline-input

Custom commands can receive values from the pipeline. This allows you to
create commands that work naturally with other Nushell commands.

For example, this custom command takes pipeline input and doubles each value:

def double [] {
    each { |x| $x * 2 }
}


You can use it as part of a pipeline:

[1 2 3] | double


Custom commands can also access all of their pipeline input through $in:

def total [] {
    $in | math sum
}


This allows the custom command to work with the entire value coming through
the pipeline:

[1 2 3 4] | total


You can learn more about closures, which are commonly used when processing
pipeline data, by running:

tutor closures

$env.config.completions.persistent_menus keeps completion and history menus open while editing [toc]

PR #18573 by @maxim-uvarov

Added $env.config.completions.persistent_menus. When set to true, an active completion or history menu stays open while you edit: erasing characters (or emptying the commandline) refilters the menu instead of closing it. Default false keeps the old behavior.

$env.config.completions.persistent_menus = true

view source --dependencies can now include custom command dependencies [toc]

PR #18801 by @maxim-uvarov

Added --dependencies (-d) to view source. It appends the source of every custom command the target calls, transitively — including commands private to a module, which cannot be viewed any other way — and prepends every constant those bodies read, with the value the engine holds:

> module m {
  const LIMIT = 42
  def helper [] { $LIMIT }
  export def bar [] { helper }
}
> use m
> view source "m bar" --dependencies
const LIMIT = 42

def "m bar" [] { helper }

def helper [] { $LIMIT }

The interactive tutor now teaches if, match, and where [toc]

PR #18972 by @nos1dot618

Added a new tutor conditional tutorial for learning conditional logic, pattern matching, and conditional filtering.

> tutor conditional

Conditional commands allow you to choose which code to run based on a value or
condition.

The if command runs a block when its condition is true:

if 5 > 3 {
    print "5 is greater than 3"
}


You can use else to run a different block when the condition is false:

let age = 20

if $age >= 18 {
    "adult"
} else {
    "minor"
}


You can also chain multiple conditions with else if:

let score = 75

if $score >= 90 {
    "A"
} else if $score >= 80 {
    "B"
} else if $score >= 70 {
    "C"
} else {
    "F"
}


The if command returns a nushell value, so it can be store in a variable or
use in a pipeline:

let result = if 10 > 5 { "yes" } else { "no" }
$result


When you have several possible values to match, the match command can be more
convenient. It checks a value against several patterns:

let number = 2

match $number {
    1 => "one",
    2 => "two",
    3 => "three",
    _ => "something else"
}

The _ pattern acts as a catch-all for anything that did not match an earlier
branch.

The match command can also be used to unpack structured values:

let user = { name: "Alice", admin: true }

match $user {
    { admin: true } => "administrator",
    { admin: false } => "regular user",
    _ => "unknown"
}


Conditions can also be used to filter values in a pipeline with the where
command:

[1 2 3 4 5] | where $it > 2

This keeps only the values for which the condition is true:

╭───┬───╮
│ 0 │ 3 │
│ 1 │ 4 │
│ 2 │ 5 │
╰───┴───╯


For tables, the where command is particularly useful for selecting rows:

ls | where size > 1kb


You can learn more about filtering pipelines with:

help where


You can learn more about blocks, which are used by the if command and other
control flow commands, by running:

tutor blocks


You can also see more details about the if and match commands with:

help if
help match

std/log commands can now attach structured context fields [toc]

PR #18971 by @neveroNiwe

Added a --context flag to all std/log emitters

Example:

> use std/log
> log info 'hello' --context {user: Ana}
2026-09-26T18:56:49,484|INF|hello user="Ana"

Build interactive terminal interfaces with tui [toc]

PR #19025 by @fdncred

Summary

This release adds a tui command family so a Nushell user can build an interactive TUI or popup from a pipeline, without writing Rust. The commands live in a new nu-tui crate; the ratatui style conversions are shared with explore.

Interactive tui run always uses the alternate screen, so the shell comes back intact when you quit. --dialog is the same session in a smaller floating window. tui debug paints the same UI to a string and reports how it was laid out, for scripts and tests.

tui run returns one record, {action, focused, selected, page, values, rows, live}, where values holds every widget's state by id. Colors come from a new $env.config.tui section (documented in config nu --doc).

This release also fixes a related memory leak: nu-utils now reads the OS locale once per process. sys_locale goes through CoreFoundation on macOS and its autoreleased objects were never collected on a plain Rust thread, so any loop that formats filesizes (the TUI redraws per frame) grew memory without bound.

Command reference

Every builder takes --id and --focus (start with that widget focused). Data widgets (table, tree, log, select, progress, label) also take --data and --from; list widgets (table, tree, select) also take --on-select and --multi. The remaining flags are listed.

CommandPositionalFlagsRole
tuiHelp listing subcommands
tui labeltext or closure--title, --statusStatic text: inline, on the title bar, or on the status bar. A closure follows a row
tui menu[items]Menu bar with mnemonics, dropdowns, and hook actions
tui textbox--placeholder, --valueEditable field
tui tablesource closure--columns, --capture-keys, --indexNavigable rows. Scalars show as one item column
tui select[items]--display, --indexRadio list, or checkbox list with --multi
tui buttonlabel, hookRuns a hook, or submits its label. Adjacent buttons share a row
tui progresssource closure--value, --total, --labelGauge fed by a value, the data, or a source row
tui logsource closure--max-linesAppend-only log. Follows the tail of a stream
tui treesource closure--walk, --columnNested records, or a directory walk
tui search--placeholder, --bind, --fuzzy, --case-sensitive, --columnsSearch box. Filters the lists in its scope
tui previewclosure--from, --max-bytesText for the selected row: a file, or whatever the closure returns
tui split[children]--vertical, --sizes, --ratioSide-by-side or stacked panes with draggable dividers
tui boxtitle, [children]A titled, bordered group
tui tabtitle, [children]A page in the tab bar
tui bindkey, hookRun a hook when a key is pressed anywhere
tui runhook--dialog, --size, --refresh, --no-mouseEvent loop
tui debughook--keys, --until, --size, --dialogHeadless render, key replay, and layout/focus introspection

Layout model

Widgets in the outer pipeline stack top to bottom, one row each. The exception is buttons: adjacent tui buttons pack onto one row, left to right (§12). tui split, tui box, and tui tab take a list of child widgets and arrange them. Children are built inside parentheses:

ls
| tui label --title "files"
| tui split --sizes [60% 1fr] [
    (tui box "list" [ (tui search --bind /) (tui table --columns [name type size]) ])
    (tui preview { nu-highlight })
  ]
| tui label --status "enter: pick  /: filter  q: quit"
| tui run

Chrome, that is tui label --title, tui label --status, and tui menu, goes in the outer pipeline only and stays visible on every page. tui tab is also outer-pipeline only. tui search can go in either place; its position decides what it filters (§3).

Auto ids are table-0, search-0, …, numbering widgets of each kind in tree order. When two children both contain a table-0, the second becomes table-1 and a --from table-0 inside that child follows it. An explicit --id is never renumbered; two of the same explicit id is an error. Pass --id when another widget needs a stable name; tui debug shows the resolved ids.

Data flow

Each widget shows the first of these that exists:

  1. its own --data, or the value piped into it inside a child list ([(ls | tui table)]);
  2. what its --from source produced (§4);
  3. the nearest ancestor container's data;
  4. the outer pipeline's data.

So one pipeline can feed every list, or each pane can have its own rows:

ls | tui split [ (tui table) (tui tree) ] | tui run           # both read ls
tui split [ (ps | tui table) (ls | tui table) ] | tui run      # each has its own
tui split [ (tui table --data (ps)) (tui table --data (ls)) ]  # the same, spelled out

A builder reads a stream for a quarter of a second. A producer that finishes in that time (ls, ps, open) is collected into the widget's data; one that keeps going (1.., tail -f) stays live and flows on to tui run (§9). A child list can only hold collected values, so keep unbounded producers in the outer pipeline.

Hook contract

One contract covers every closure that reacts to the user: tui bind, menu actions, tui button, --on-select, and the tui run closure. The hook receives the state record (the same record tui run returns, §Result record) as $in, and as its first parameter when it declares one. Its output decides what happens:

ReturnsEffect
nothingnothing changes
{action: submit, selected: ...}the TUI closes with that selection
{action: quit}the TUI closes without a selection
anything elseit replaces the shared data list; every widget reading it redraws

An error goes to the status bar as error:… and the TUI stays open.

ls
| tui table
| tui bind ctrl+r {|| ls }                                              # reload
| tui bind s {|state| {action: submit, selected: $state.selected.name} } # submit the name
| tui run

nu --dap starts a Debug Adapter Protocol server for Nushell scripts [toc]

PR #18738 by @rvhelden

Added a Debug Adapter Protocol server to Nushell. Running nu --dap starts a DAP server over stdio, so any DAP-capable editor (VS Code, Zed, Neovim, …) can debug .nu scripts — set breakpoints (including conditional breakpoints and logpoints), step through code and pipelines, inspect variables and $env, evaluate watch expressions, and even step backward through a recorded timeline.

Completion input now exposes the command being completed [toc]

PR #19054 by @philocalyst

Added place.command to completion input records. Custom completers that declare place can now read the command being completed as a list of shell words, so external completers can reliably use $place.command.0 and ...$place.command even after pipes, semicolons, inside closures, or inside subexpressions.

Sourced menus now refresh correctly after partial completion [toc]

PR #19054 by @philocalyst

Fixed sourced menus with partial completion enabled so Tab completion refreshes against the updated line after inserting a common prefix. This avoids corrupting the command line or replacing the wrong span, such as bits r becoming bits ror o instead of bits ror.

Other additions [toc]

  • Floating point number strings may now be parsed via into float if they use a comma as decimal separator. (#18882)
  • to yaml --non-roundtrip now also accepts a raw null instead of only "null" for the null configuration. (#18851)
  • Allow take until, take while, skip until, skip while, and chunk-by to use row condition syntax alongside closures. (#18844)
  • Include UTC offset in date list-timezone output. (#18922)
  • You can now hash a value using the sha512 algorithm using the hash sha512 built-in. (#19027)
  • Added mkdir --fail-if-exists <dir>, which errors if the directory already exists instead of silently succeeding. Default mkdir behavior is unchanged. (#19021)
  • save --force now creates missing parent directories before writing the destination file. (#19039)
  • update cells has a new --recursive (-r) flag. With it, the closure runs on every leaf value inside nested records and lists instead of on the containing cell as a whole. The default behavior is unchanged. (#19060)
  • Added forward slash and backslash to char, independent of the underlying operating system. (#19082)
  • Added the SwitchMode keybinding event, { send: SwitchMode, mode: vi_normal }, taking the same mode names mode takes on a keybinding. A switch into the mode already active reports itself inapplicable, so an until list falls through to its next event where it used to stop; ViChangeMode and HelixChangeMode share that. (#19077)
  • Added vi_visual as a keybinding mode and $env.config.cursor_shape.vi_visual, which follows vi_normal while left on inherit. Bindings for vi_normal no longer apply in visual mode. (#19077)

Performance [toc]

Faster typing of use in the REPL [toc]

PR #18841 by @fdncred

The REPL no longer parse-time-loads a module just to syntax-highlight it. Typing use std or use std/iter no longer stalls on the first exact match of std (most noticeable in debug builds). Execution is unchanged: the module still loads when you run the line.

Completing use std/ (and export use / overlay use) lists virtual standard-library children without walking the current directory. $NU_LIB_DIRS is still searched. Completing a real path such as use ./foo/ is unchanged.

Syntax highlighting also does less work per keystroke: it reuses the last parse of the same line (for example when only the cursor moves) and copies less text while painting.

# These should feel instant to type in the REPL, including debug `cargo run`
use std
use std/iter
use std/assert

$nu.startup-time is now accurate and Nushell starts faster with large configs [toc]

PR #19049 by @fdncred

More accurate startup reporting

$nu.startup-time now measures the time until the first prompt is ready, starting at process creation on macOS and Windows, or at main on other platforms. This includes config files, plugins, env_change and pre_prompt hooks, and prompt evaluation. Startup hooks see a provisional value; the final value is available from the first command onward. Scripts also get a startup time instead of -1ns.

The banner's "Startup Time" line now appears after the startup hooks, just before the first prompt, so it shows the final value. The welcome message still appears first, with hook output between it and the timing line. Use banner --no-startup-time to hide the timing line.

For a closer look, --log-level perf reports time spent before main, in engine setup, and loading the standard library, followed by a final "startup (process start to first prompt)" line.

Faster loading and commands

Command lookups no longer rebuild overlay visibility maps, roughly halving config load time for configs that use many modules. Loading the plugin registry is also faster: about 5× for a registry with 20 plugins.

gstat finds the nearest tag faster in large repositories—about 4× in the Nushell repo—with unchanged output. When no terminal is attached, table and term size avoid spawning tput and use COLUMNS/LINES, falling back to 80×24.

Other performance improvements [toc]

  • Optimize style_computer.rs#style_primitive to use shallow_get_type() instead of get_type() (#18975)
  • Improved parsing performance: scripts, modules and sourced files parse about 1.4-1.5x faster, and the REPL's per-keystroke parse benefits accordingly. No change to what is accepted, rejected, or reported. (#19055)

Other changes

The MCP HTTP server now listens only on 127.0.0.1 by default [toc]

PR #18952 by @ayax79

The MCP HTTP server now binds to 127.0.0.1 by default instead of 0.0.0.0, so it is no longer exposed to other hosts on the network unless explicitly configured.

Added --mcp-host for choosing the MCP HTTP bind address. Use --mcp-host 0.0.0.0 with --mcp-transport http if you intentionally want the MCP server to listen on all interfaces.

Additional changes [toc]

  • The each command's documentation now includes more information on supported input types. (#18893)
  • Refreshing $env.ENV_CONVERSIONS now also normalizes PATH into its usual list form. The load-env help documents how to refresh environment conversions after importing string values. (#18832)

Bug fixes [toc]

lines --skip-empty now works consistently across input types [toc]

PR #18872 by @fdncred

lines --skip-empty now skips empty lines for string and byte stream input, not only list streams.

> "foo\n\nbar" | lines --skip-empty
╭───┬─────╮
│ 0 │ foo │
│ 1 │ bar │
╰───┴─────╯

Whitespace-only lines are treated as empty, same as they already were for list streams.

format pattern and parse now reject unclosed { patterns [toc]

PR #18871 by @fdncred

format pattern already reported a delimiter error for a lone }. A pattern that ended with { succeeded and dropped the brace. parse simple patterns did the same.

Both commands now treat an unescaped { without a matching } as a delimiter error.

> {} | format pattern '{'
Error: nu::shell::delimiter_error

  × Delimiter error
   ╭─[repl_entry #20:1:6]
 1 │ {} | format pattern '{'
   ·      ───────┬──────
   ·             ╰── there are unmatched curly braces
   ╰────

> "hello " | parse "hello {"
Error: nu::shell::delimiter_error

  × Delimiter error
   ╭─[repl_entry #21:1:18]
 1 │ "hello " | parse "hello {"
   ·                  ────┬────
   ·                      ╰── Found opening `{` without an associated closing `}`
   ╰────

Escaped braces ({{ and }}) still insert a literal brace. A lone } in parse is still a literal character to match, not an error. parse --regex is unchanged.

into string now preserves string typing for semver values [toc]

PR #18901 by @fdncred

> let s = "1.0.0" | into semver | into string
> $s | describe
string
> "/tmp" | path join ("1.115.0" | into semver | into string)
/tmp/1.115.0

format date handles locale-specific formats correctly [toc]

PR #18918 by @aron-intframe

PR #18924 by @aron-intframe

format date now handles %E and %O modifiers in locale-specific formats. Under locales such as Thai (th_TH) and Lao (lo_LA), %x, %X and %c render in the locale's own field order, without the era. This also fixes startup errors from the default config's date now | format date '%x %X'.

Thai locale
> $env.LC_TIME = "th_TH.UTF-8"
> date now | format date '%c'
ส. 26 ก.ย. 26, 20:30:58

Explicit modifiers work too: %Ey and %Od render as %y and %d would. For locales without an AM/PM format, including az_IR and fa_IR, %r falls back to the locale's plain time format and handles its modifiers:

Persian (Iran) locale
> $env.LC_TIME = "fa_IR.UTF-8"
> date now | format date %r
20:34:19

Other locales, including de_DE, fr_FR and nl_NL, continue to render as before.

Faster repeated source of the same file [toc]

PR #18948 by @fdncred

0.115 started re-parsing every source / source-env of a file that had already been parsed, so configs and libraries that source the same helpers many times got slower as more files were loaded. A 63-file case that stayed around 50ms in 0.114 grew to hundreds of milliseconds.

This release restores safe reuse of cached blocks for source and source-env. Libraries without captured values can use the cache, as in 0.114, while blocks with stale captures are parsed again to keep their values up to date.

Redirected nu --help output no longer contains ANSI color escapes [toc]

PR #18899 by @catlover-bot

nu --help no longer writes ANSI escape sequences when its stdout is redirected to a pipe or file.

For example:

nu --help > help.txt

Now produces plain text instead of ANSI-colored text.

Table display now respects $env.config.table.trim wrapping and truncating more consistently [toc]

PR #18979 by @fdncred

Fixed $env.config.table.trim so wrapping and truncating actually differ on default table display (table -e on terminals 100 columns or wider), including with header_on_separator.

ModeBehavior
WrappingShows more columns, wrapping long cells onto extra lines.
TruncatingKeeps one line per row, drops extra columns with a trailing ..., and marks cut cells with truncating_suffix.

In both modes, columns are no longer squeezed to a single character, avoiding the vertical s/i/z/e layout for size. The trailing ... column indicates omitted columns; truncating_suffix only marks a visible cell whose content was cut.

Examples:

Wrapping
> $env.config.table.trim = { methodology: wrapping, truncating_suffix: "..." }
> ls -al | first 5
╭───┬─────────────────────────────────────────┬──────┬────────┬──────────┬────────┬────────┬─────╮
│ # │                  name                   │ type │ target │ readonly │  size  │ create │ ... │
│   │                                         │      │        │          │        │ d      │     │
├───┼─────────────────────────────────────────┼──────┼────────┼──────────┼────────┼────────┼─────┤
│ 0 │ .abc___________________________________ │ file │        │ false    │    0 B │ a minu │ ... │
│   │                                         │      │        │          │        │ te ago │     │
│ 1 │ .cargo                                  │ dir  │        │ false    │    0 B │ a year │ ... │
│   │                                         │      │        │          │        │  ago   │     │
│ 2 │ .git                                    │ dir  │        │ false    │ 4,0 kB │ 2 year │ ... │
│   │                                         │      │        │          │        │ s ago  │     │
│ 3 │ .gitattributes                          │ file │        │ false    │  113 B │ 3 mont │ ... │
│   │                                         │      │        │          │        │ hs ago │     │
│ 4 │ .githooks                               │ dir  │        │ false    │    0 B │ 3 mont │ ... │
│   │                                         │      │        │          │        │ hs ago │     │
╰───┴─────────────────────────────────────────┴──────┴────────┴──────────┴────────┴────────┴─────╯
Truncating
> $env.config.table.trim = { methodology: truncating, truncating_suffix: "..." }
> ls -al | first 5
╭───┬─────────────────────────────────────────┬──────┬────────┬──────────┬────────┬────────┬─────╮
│ # │                  name                   │ type │ target │ readonly │  size  │ cre... │ ... │
├───┼─────────────────────────────────────────┼──────┼────────┼──────────┼────────┼────────┼─────┤
│ 0 │ .abc___________________________________ │ file │        │ false    │    0 B │ 2 m... │ ... │
│ 1 │ .cargo                                  │ dir  │        │ false    │    0 B │ a y... │ ... │
│ 2 │ .git                                    │ dir  │        │ false    │ 4,0 kB │ 2 y... │ ... │
│ 3 │ .gitattributes                          │ file │        │ false    │  113 B │ 3 m... │ ... │
│ 4 │ .githooks                               │ dir  │        │ false    │    0 B │ 3 m... │ ... │
╰───┴─────────────────────────────────────────┴──────┴────────┴──────────┴────────┴────────┴─────╯

length, columns, and is-empty now surface errors from streamed input [toc]

PR #18976 by @sidsri14

Fixed an issue where length, columns, and is-empty / is-not-empty could silently ignore errors in streamed input and return incorrect results instead of surfacing the original error.

For example, [[name size]; [a 100b] [b 200b]] | where size <= 150 | length now errors with nu::shell::operator_incompatible_types instead of returning 2, and likewise for columns / is-empty.

> [[name size]; [a 100b] [b 200b]] | where size <= 150 | length
Error: nu::shell::operator_incompatible_types

  × Types 'filesize' and 'int' are not compatible for the '<=' operator.
   ╭─[repl_entry #52:1:18]
 1 │ [[name size]; [a 100b] [b 200b]] | where size <= 150 | length
   ·                  ──┬─                         ─┬ ─┬─
   ·                    │                           │  ╰── int
   ·                    │                           ╰── does not operate between 'filesize' and 'int'
   ·                    ╰── filesize
   ╰────

Chained par-each pipelines no longer deadlock on same-size thread pools [toc]

PR #18999 by @zozo123

Chaining par-each commands with the same thread count could cause a pipeline to hang. The commands could share a thread pool while both were still running: the earlier stage would wait for the next stage to consume its output, while the next stage waited for a free worker.

This release reuses cached thread pools only when they are idle. Stages running at the same time use separate pools, allowing pipelines like this to finish:

> 0..99
| par-each --threads 1 {|it| $it }
| par-each --threads 1 {|it| $it }
| length
100

Expanded nested tables now keep their table borders when cells wrap [toc]

PR #19007 by @fdncred

table --expand now preserves the borders of nested tables, including those in plugin list output. Previously, wrapping a nested table as plain text could break its layout.

Long cells wrap or truncate within the nested table according to $env.config.table.trim, keeping its structure intact. Scalar values in the outer table continue to follow the same wrapping or truncation setting.

mkdir --verbose no longer reports existing directories as newly created [toc]

PR #19017 by @Developer1010x

Fixed mkdir --verbose reporting created: true for directories that already existed. Such rows now report created: false. Directories that are actually created are unaffected.

finally now always runs, in the right order, however a try block is left [toc]

PR #19052 by @fdncred

Cleanup runs in the right order

When an outer catch handles an error, every finally block between the error and that handler now runs, innermost first. This also applies to errors raised inside a catch or another finally block. An error raised in finally still replaces the original error.

An error or return inside try now runs finally and takes effect without executing the statements after the try expression. Likewise, break and continue run finally before control returns to the loop. They also leave error handlers intact, fixing cases where a later, unrelated error triggered a leftover handler.

Consistent input to finally

$in is now always defined inside finally and matches the block's optional parameter (finally {|x| ... }):

How try/catch completesValue passed to finally
SuccessThe value produced by try/catch
ErrorThe error record
return, exit, break or continuenothing

Changes to view ir

view ir now shows begin-finally, end-finally and unwind-jump in place of pop-finally. The register-less finally instruction has also been removed.

List literals and match patterns now reject semicolon separators [toc]

PR #19063 by @windlandneko

List literals and match list patterns now reject unexpected semicolon separators instead of silently accepting malformed input or discarding subsequent content.

Header-only table syntax such as [[a b];] now also produces a parse error.

> [[a b];]
Error: nu::parser::parse_mismatch

  × Parse mismatch: expected table row.
   ╭─[repl_entry #60:1:8]
 1 │ [[a b];]
   ·        ▲
   ·        ╰── expected table row
   ╰────
  help: Check the syntax around this position — a typo, missing delimiter, or wrong separator is common.

LSP hover tooltips now render Markdown without accidental bold text [toc]

PR #19080 by @fdncred

LSP hover descriptions now render as normal text. A missing blank line before the Markdown separator made the description look like a heading instead.

Before

Renders some greeting message

Usage

hello {flags}
After

Renders some greeting message


Usage

hello {flags}

* These previews are approximations for illustration, not actual LSP output. The exact appearance depends on your editor.

External completers now receive expanded alias commands and show warnings after menus close [toc]

PR #19085 by @kronberger-droid

External completers receive the command name and its arguments in $place.command, with one list item per shell word. This list describes the command at the cursor, including when it appears after a pipe or ;, or inside a closure.

For example, this completer passes the command name and argument list to Carapace:

$env.config.completions.external.completer = {|place|
  carapace $place.command.0 nushell ...$place.command | from json
}

Aliases are expanded before the list reaches the completer. If gco is an alias for git checkout, typing gco ma gives the completer [git, checkout, ma].

The legacy spans input receives the same list. Incomplete arguments stay together: typing foo [a b produces [foo, "[a b"], keeping the unfinished list as one argument instead of splitting it into brackets, words and spaces.

Deprecation warnings for menu source configurations now appear after the command line is handed back, once the completion menu has closed. This keeps warnings from appearing over the menu.

Other fixes [toc]

  • 2 issues were identified which may result in invalid suggestions when an unresolved command is entered. (#18728)
  • Fixed an issue where YAML values containing .inf or .nan as embedded text could be incorrectly converted to floating-point values. Values such as a.infra and a.nanotube now remain strings when decoded with from yaml. (#18897)
  • Invalidate the config any time anything changes under $env.config (#18950)
  • Nushell now supports color coded ls output for a broader range of files by default (e.g. .avif, .odin, etc.), with the exception of .kex which has been removed. .csv has a new default color value. (#18937)
  • Fixed an issue in keybindings listen where Esc wouldn't quit if a state (e.g. NumLock or CapsLock) was reported. (#18867)
  • try with a catch or finally block no longer prints a stray blank line after an external command's output. (#18811)
  • Fixed an issue where each while silently stopped when the closure or input ByteStream produced an error. These errors are now preserved and reported. (#18958)
  • External command arguments beginning with { are now parsed as closures or records; literal curly-braced arguments must be quoted. (#18837)
  • Fixed an issue where --ide-check silently succeeded when the target file could not be read. Nushell now reports the file read error and exits with a non-zero status. (#18961)
  • Fixed an issue in workspace compilation where using the "plugin" feature flag that would result in a compilation error. (#18988)
  • Fixed an issue where commandline complete ignored an external completer assigned to $env.config.completions.external.completer earlier in the same script. (#19012)
  • Adds a default value to error make's labels text (#19037)
  • Fixed query web -t [] failing with plugin_failed_to_decode on HTML tables that have no <th> headers and more than one row. Such tables now produce one record per row with generated column0, column1, ... column names. (#19041)
  • Fixed a panic when printing empty lists/records or narrow-fitting tables on a zero-column pty (e.g. some CI environments). Nushell now falls back to plain text output or a warning instead of crashing. (#19045)
  • mktemp --directory is now relative to the working directory if a template is passed (#18996)
  • default now accepts cell paths for its column arguments, so default 5 a.b fills the nested field b inside a (creating a if needed) instead of adding a literal "a.b" key. Quote the argument, as in default 5 "a.b", to target a key that actually contains a dot. (#19058)
  • Fixed an issue where flatten silently dropped a nested record field when a top-level column of the same name came later in the record. The nested field is now renamed to <parent>_<field>, as it already was for the opposite field order. The flatten help text now describes how record input is handled. (#19059)
  • Fixed an issue where std dt datetime-diff reported an incorrect day count when the difference crossed a month boundary — for example, the difference between 2021-01-15 and 2021-03-01 was 1month 17days instead of the correct 1month 14days. This also corrects the standard-library startup banner, which formats its uptime with datetime-diff via pretty-print-duration. (#19064)
  • Fixed rm with leading-dot globs such as rm -r dir/.* on Windows deleting dir and its parent directory. The . and .. entries are now skipped on all platforms. (#19065)
  • table --theme markdown and table --theme restructured (and the matching $env.config.table.mode values) now always produce valid Markdown / reStructuredText, even when $env.config.table.header_on_separator is enabled. (#19066)
  • Fixed rm --interactive on Windows answering two prompts with a single key press. (#19067)
  • Fixed idx search returning at most 200 matches per file and ignoring the exact --limit value. (#19078)
  • Fixed an issue where Nushell ignored XDG_CONFIG_HOME for users without a home directory. Config loads from XDG_CONFIG_HOME again, and $nu.home-dir reports an error when there is no home directory. (#19083)
  • Fixed path relative-to providing improper error messages when its argument was not a parent of the input. (#18792)
  • view source now renders a rest parameter as ...rest: string rather than ...rest:string, matching how it already renders every other parameter. (#19024)

Notes for plugin developers [toc]

  • Fixed compiling nu-plugin-test-support by default together with nu-plugin. (#18947)

Hall of fame [toc]

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

authorchangelink
@cptpiepmatzRemove most fs helpers from nu-test-support#18910
@fdncredFix completion tests by resolving ".." in WORKSPACE_ROOT path#18941
@fdncredIR-shaped const evaluation for run_const (AST migration phase 2)#18967
@hustcerFix nushell command docs build error#19084

Full changelog [toc]

authortitlelink
@Developer1010xfix(mkdir): don't report an existing directory as created in --verbose#19017
@Developer1010xdocs(mkdir): the --verbose example showed output that never occurs#19023
@Developer1010xfix(view source): put a space after the colon on a rest parameter#19024
@Dheebzfix(env): normalize PATH when refreshing ENV_CONVERSIONS#18832
@Dheebzfix(parser): parse brace expressions in external calls#18837
@Dheebzfix: use stack config for commandline completions#19012
@DoruminDon't go to tmp if --directory#18996
@Jorge-Polanco-Roquefeat(mkdir): add --fail-if-exists flag to error on existing directory#19021
@KaiSforzaerror make: Allow no text value#19037
@KaiSforzascripts/nix: Update the flake lock#19038
@LouisDeconinckfix(query web): parse headerless tables row by row#19041
@LouisDeconinckfix(table): don't panic when the terminal is too narrow to draw#19045
@Mrfiregemlet more commands use row conditions#18844
@MrfiregemInclude UTC offset in date list-timezone output#18922
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.85.11 to 2.86.6#18904
@app/dependabotbuild(deps): bump uuid from 1.24.0 to 1.25.0#18906
@app/dependabotbuild(deps): bump tango-bench from 0.7.2 to 0.8.0#18907
@app/dependabotbuild(deps): bump crate-ci/typos from 1.48.0 to 1.50.0#18954
@app/dependabotbuild(deps): bump hustcer/milestone-action from 3.1 to 3.2#18955
@app/dependabotbuild(deps): bump ureq from 3.3.0 to 3.4.0#18957
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.86.6 to 2.87.7#18990
@app/dependabotbuild(deps): bump crate-ci/typos from 1.50.0 to 1.50.1#18991
@app/dependabotbuild(deps): bump the uutils group with 8 updates#18992
@app/dependabotbuild(deps): bump aws-config from 1.10.0 to 1.12.0#18994
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.7 to 2.87.12#19028
@app/dependabotbuild(deps): bump actions-rust-lang/setup-rust-toolchain from 1.17.0 to 2.0.0#19029
@app/dependabotbuild(deps): bump dirs from 6.0.0 to 7.0.0#19030
@app/dependabotbuild(deps): bump tabled from 0.21.0 to 0.22.0#19031
@app/dependabotbuild(deps): bump taiki-e/install-action from 2.87.12 to 2.87.17#19068
@app/dependabotbuild(deps): bump crate-ci/typos from 1.50.1 to 1.50.2#19069
@app/dependabotbuild(deps): bump rstest from 0.26.1 to 0.27.0#19070
@app/dependabotbuild(deps): bump serde-saphyr from 1.2.0 to 1.3.0#19071
@aron-intframefix(format date): render locales whose format carries %E or %O#18918
@aron-intframefix(format date): resolve %r when the locale's am/pm fallback also carries %O#18924
@ayax79Polars date range#18887
@ayax79MCP: set default bind host to 127.0.0.1#18952
@bobisageekfix keybindings listen - ignore KeyEventState when checking for Esc#18867
@catlover-botfix: strip ANSI from redirected CLI help#18899
@costajohntfix(config): keep XDG config when there is no home directory#19083
@cptpiepmatzAllow raw null as a value for to yaml --non-roundtrip#18851
@cptpiepmatzAllow float value strings with commas in into float#18882
@cptpiepmatzPrepare patch release#18884
@cptpiepmatzBump patch version after release#18885
@cptpiepmatzRemove most fs helpers from nu-test-support#18910
@cptpiepmatzPropagate local-socket feature into nu-plugin-test-support#18947
@cptpiepmatzReplace to yaml --compact-list-indent with --list-indent#19005
@cuishuangide: report file read failures from --ide-check#18961
@dilrDocument behavior of each for more types of inputs.#18893
@fdncrednamed parameters can pass null or omit parameter entirely for easier shadowing#18796
@fdncredreduce ast dependency for ir calls - phase 1#18813
@fdncredperf - stop parse-time-loading modules and extra cwd walks while typing use std/#18841
@fdncredfix unmatched { at end of format pattern and parse patterns#18871
@fdncredfix lines --skip-empty for string and byte stream input#18872
@fdncredfix: infer string from semver | into string.#18901
@fdncredfix(tests): fix completion tests by resolving ".." in WORKSPACE_ROOT path#18941
@fdncredupdate proc_macro_error to 3 and other dependencies#18945
@fdncredupdate fff-search to 0.10.6#18946
@fdncredfix parsing performance regression#18948
@fdncredwhen config changes invalidate cache#18950
@fdncredbump reedline to a8e9364#18959
@fdncredengine: IR-shaped const evaluation for run_const (AST migration phase 2)#18967
@fdncredbump rust toolchain to 1.96.1#18968
@fdncredfix table truncating vs wrapping#18979
@fdncredfix nested table after wrapping/truncating changes#19007
@fdncredRevert "mkdir errors on already-created dir"#19008
@fdncredthe tui family of commands#19025
@fdncredupdate rustls & friends#19026
@fdncredupdate some deps#19034
@fdncredbump uu_* crates to 0.12.0#19040
@fdncredperf(startup): make $nu.startup-time accurate and speed up config loading, plugin registry, and gstat#19049
@fdncredfix(engine): run every finally on the way out of nested try blocks, and unwind break/continue through them#19052
@fdncredperf(parser): reduce parse time by 30% - 50%#19055
@fdncredbump fff-search to 0.11.0#19057
@fdncredfix(default): accept cell paths for column arguments#19058
@fdncredfix(flatten): keep nested fields that collide with top-level columns#19059
@fdncredfeat(update cells): add --recursive flag to visit nested leaf values#19060
@fdncredfix lsp hover tooltip markdown#19080
@fly1dfix(yaml): do not parse embedded float tokens#18897
@hexbinoctDon't print a stray blank line when try with catch or finally collects an external#18811
@hustcerFix nushell command docs build error#19084
@i-apidocs(nuon): add a specification of the NUON format#18925
@kronberger-droidchore(reedline): bump reedline to 73b928a#18890
@kronberger-droidchore(reedline): bump reedline fc19b91#18892
@kronberger-droidfix(nix): bump rust-overlay so the 1.96.1 toolchain resolves#18985
@kronberger-droidchore: bump reedline 06bf606#18986
@kronberger-droidchore: bump reedline to 436f17b#19013
@kronberger-droidchore(reedline): bump reedline to e0f1c0b#19042
@kronberger-droidfix(reedline): forward Menu::settings through SourcedMenu#19043
@kronberger-droidfix(ci): run ready_for_review CI on the PR head, not on main#19047
@kronberger-droidfeat(reedline): bump to db34d84#19077
@kronberger-droidfix(completions): expand alias heads in place.command, keep completer warnings off the menu#19085
@luangucuneach while: preserve errors instead of silently stopping#18958
@magnify035chore(ls): update default color mappings#18937
@maxim-uvarovAdd completions.persistent_menus config option#18573
@maxim-uvarovView source dependencies#18801
@mikehasafix(std/dt): correct datetime-diff day count when borrowing a month#19064
@mkatychevfix(nu-plugin): add socket feature flag to handle --no-default-features correctly#18988
@mrhard9090fix(rm): skip . and .. glob matches on Windows#19065
@mrhard9090fix(table): keep markdown and restructured headers off the separator#19066
@mrhard9090fix(rm): answer one --interactive prompt per key press on Windows#19067
@mrhard9090fix(idx search): don't cap matches at 200 per file#19078
@neveroNiweAdd structured context support to std/log#18971
@nos1dot618docs(tutor): add reedline shortcuts tutorial and document $env#18903
@nos1dot618docs(tutor): add custom commands and pipeline input tutorials#18927
@nos1dot618docs(tutor): add conditional(if, match, where) tutorials#18972
@pheentyfix improper cant convert error in path-relative-to#18792
@philocalystUnified Completions#18791
@philocalystfixes for unified/completions in general#19054
@pickxroundup of 2 fixes for "did you mean?"#18728
@pickxmkdir errors on already-created dir#19006
@pickxchar: add forward slash/backslash.#19082
@rvheldenAdd a nu-dap crate and nu --dap: a Debug Adapter Protocol server for Nushell#18738
@sebaschifeat(hash): add sha512 subcommand#19027
@sidsri14fix: propagate error stream values in length, columns, and is-empty#18976
@surmafeat(save): create parent directories with --force#19039
@user93390update(style_computer.rs): fixed unessesary string allocations#18975
@windlandnekofix(parser): reject unexpected semicolons in list literals and patterns#19063
@zozo123Test Incredibuild self-hosted runner in CI#18810
@zozo123Fix par-each deadlock when chaining same-size thread pools#18999
Edit this page on GitHub
Contributors: Piepmatz, Tim 'Piepmatz' Hesse