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

Today, we're releasing version 0.105.0 of Nu. This release adds support for stored closures in the where command, making filter obsolete, improved deprecation tools for custom commands, case-sensitive cell-path handling with new syntax for case-insensitivity, a powerful new recurse command to explore nested data, a full switch from OpenSSL to Rustls for simpler Linux builds, smarter HTTP commands that add http:// by default, and several new features and improvements to Polars integration.

Thank you to all those who have contributed to this release through the PRs below, issues and suggestions leading to those changes, and Discord discussions.

Where to get it

Nu 0.105.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
    • One where to rule them all
    • Better deprecations
    • oneof the things
    • Case-sensitive cell-paths or not!
    • recurse'ively explore nested values
    • No more openssl
    • Better Windows releases
    • HTTP by default
    • More Polars
  • Changes
    • Additions
      • Ignore fields in simple parse patterns with _
      • Lazy closure evaluation for default
      • path join can now read byte stream input
      • run-external spreads command if it's a list
      • Improvements to bench
      • overlay new -r can now reset overlays
      • See env variables as externals would
      • Use PowerShell scripts from the $env.PATH
      • Make your table look like they are from neovim
      • Center columns via to md --center
      • Prefer OSC 9;9 on Windows over OSC 7
      • Disable expensive calculations with gstat --disable-tag
      • Know what open and save can do with std/help
      • Content type of view span
    • Breaking changes
      • Cell-paths with case-sensitivity and without!
      • Paths on lazy frames now produce expressions
    • Bug fixes and other changes
  • Notes for plugin developers
    • Construct IoError from std::io::Error instead of std::io::ErrorKind
  • Hall of fame
  • Full changelog

Highlights and themes of this release [toc]

One where to rule them all [toc]

where used to support only row conditions and literal closures for filtering rows. If you wanted to use stored closures, you had to use filter.

In #15697, @Bahex added stored closure support to where, making filter obsolete. Because of this, filter was marked deprecated in #15867. @132ikl updated the docs accordingly in #15467.

Now, where can be used as a drop-in replacement for filter.

Better deprecations [toc]

You can now use the @deprecated attribute on custom commands to mark them as deprecated, thanks to @132ikl in #15770. Pass a string as the first argument to show a custom deprecation message. You can also add flags to give more details:

  • --flag: mark a flag as deprecated
  • --since: specify when the deprecation started
  • --remove: indicate when this command or flag will be removed
  • --report: use "first" or "every" to control how often users see the warning

For example:

@deprecated "Use my-new-command instead."
@category deprecated
def my-old-command [] {}

oneof the things [toc]

Built-in commands have long used SyntaxShape::OneOf to accept multiple possible types. Custom commands couldn't do this until #15646, when @Bahex added the oneof<...> type to declare type alternatives.

Example:

def foo [
    param: oneof<binary, string>
] { .. }

Case-sensitive cell-paths or not! [toc]

Before, it wasn't clear if cell-paths were case-sensitive, so some commands expected case sensitivity while others didn't. @Bahex fixed this in #15692.

Now, all cell-paths are case-sensitive by default. If you add a ! after a path element, that element becomes case-insensitive.

For example, foo.bar!.baz matches:

  • foo.bar.baz
  • foo.BAR.baz
  • foo.BaR.baz

but not:

  • FOO.bar.baz
  • foo.BAR.BAZ

The --sensitive and --insensitive flags still work but some are now deprecated. $env remains a special record with always case-insensitive cell-paths.

You can also use the new syntax to say: get "foo" case-insensitively, or return nothing if not found: get foo?!.

recurse'ively explore nested values [toc]

This release adds a new recurse command in std-rfc/iter, as an equivalent to jq's recurse/...

It recursively descends its input and returns a stream of all "descendant" values, along with their cell-path relative to the input value. It is especially useful for exploring and searching through deep trees.

{
    "foo": {
        "egg": "X"
        "spam": "Y"
    }
    "bar": {
        "quox": ["A" "B"]
    }
}
| recurse
| update item { to nuon }
# => ╭───┬──────────────┬───────────────────────────────────────────────╮
# => │ # │     path     │                     item                      │
# => ├───┼──────────────┼───────────────────────────────────────────────┤
# => │ 0 │ $.           │ {foo: {egg: X, spam: Y}, bar: {quox: [A, B]}} │
# => │ 1 │ $.foo        │ {egg: X, spam: Y}                             │
# => │ 2 │ $.bar        │ {quox: [A, B]}                                │
# => │ 3 │ $.foo.egg    │ "X"                                           │
# => │ 4 │ $.foo.spam   │ "Y"                                           │
# => │ 5 │ $.bar.quox   │ [A, B]                                        │
# => │ 6 │ $.bar.quox.0 │ "A"                                           │
# => │ 7 │ $.bar.quox.1 │ "B"                                           │
# => ╰───┴──────────────┴───────────────────────────────────────────────╯

recurse can also take a cell-path (or even a closure) to limit how it descends through its input, making it well suited to dealing with document formats like XML. Here's an example using it to extract titles from the Nushell RSS feed:

http get 'https://www.nushell.sh/rss.xml'
| recurse content
| get item
| where ($it | describe -d).type == record and $it.tag? == title
| get content.content
| flatten
# => Nushell
# => This Week in Nushell #302
# => This Week in Nushell #301
# => Nushell 0.104.1
# => This Week in Nushell #300
# => This Week in Nushell #299
# => This Week in Nushell #298
# => This Week in Nushell #297
# => Nushell 0.104.0
# => This week in Nushell #296

No more openssl [toc]

If you've built nushell on Linux, you probably had to install openssl libraries because we linked to it by default. This version switches fully to rustls, a pure Rust TLS library, making builds simpler. The change was made by @cptpiepmatz in #15810, and #15812 added support for older platforms.

If you still need openssl, build with --no-default-features --features plugin,trash-support,sqlite,native-tls.

Better Windows releases [toc]

Thanks to @hustcer, our Windows releases are now much improved. Check out the Nushell 0.104.1 blog post for more details.

HTTP by default [toc]

Running http get example.com used to fail because the command needed a full URL. @noahfraiture fixed this in #15804 by letting Nushell add http:// when the scheme is missing.

Now you can write:

  • http get example.com
  • http get :8000 goes to http://localhost:8000

More Polars [toc]

This release adds several new polars commands:

  • polars struct-encode-json by @ayax79 in #15678
  • polars horizontal by @pyz4 in #15656
  • polars replace by @pyz4 in #15706

Also, polars first now works with polars group-by thanks to @ayax79 in #15855.

Thanks to @pyz4, polars unique (#15771), polars shift (#15834), and polars group-by --maintain-order (#15865) now accept expression inputs.

@pyz4 also added new polars math expressions in #15822.

Changes [toc]

Additions [toc]

Ignore fields in simple parse patterns with _ [toc]

@132ikl added the option to use the placeholder _ to ignore fields in #15873.

"hello world" | parse "{foo} {_}"
# => ╭───┬───────╮
# => │ # │  foo  │
# => ├───┼───────┤
# => │ 0 │ hello │
# => ╰───┴───────╯

Lazy closure evaluation for default [toc]

default can now take a closure for a default value instead of a direct value thanks to @Mrfiregem in #15654. These closure are lazily evaluated and cached.

ls | default { sleep 5sec; 'N/A' } name # => No-op since `name` column is never empty
ls | default { sleep 5sec; 'N/A' } foo bar # => creates columns `foo` and `bar`; only takes 5 seconds since closure result is cached

path join can now read byte stream input [toc]

When commands return a path, thanks to @Mrfiregem in #15736, you can now call path join directly without having to use collect.

^pwd | path join foo

run-external spreads command if it's a list [toc]

With the addition of #15776 by @Mrfiregem, run-external (or calling an external) can now use a list to support arguments.

$env.config.buffer_editor = ["emacsclient", "-s", "light", "-t"]
run-external $env.config.buffer_editor foo.text

Improvements to bench [toc]

@Tyarel8 added some improvements to bench in #15843 and #15856. It is now possible to pass multiple closures into bench to compare and added the flags:

  • --warmup
  • --setup
  • --prepare
  • --cleanup
  • --conclude
  • --ignore-errors

overlay new -r can now reset overlays [toc]

@WindSoilder added the option to reset new overlays via overlay new -r in #15849.

See env variables as externals would [toc]

In #15875 did @cptpiepmatz add the command debug env to get a record of how an external would get the environment variables. This includes handling the $env.PATH and all env conversions.

Use PowerShell scripts from the $env.PATH [toc]

@fdncred made it possible in #15760 to execute powershell scripts from anywhere if they are in the $env.PATH.

Make your table look like they are from neovim [toc]

@gmr458 added the new table mode "single" to $env.config.table.mode in #15672. It looks like the "default" with sharp corners or "heavy" with thinner lines:

$env.config.table.mode = "single"
scope commands | select name category | first 2
# => ┌───┬───────┬──────────┐
# => │ # │ name  │ category │
# => ├───┼───────┼──────────┤
# => │ 0 │ alias │ core     │
# => │ 1 │ all   │ filters  │
# => └───┴───────┴──────────┘

Center columns via to md --center [toc]

@lazenga added in #15861 the flag --center to to md. With it you can pass a list of cell-paths to center in the markdown output.

version | select version build_time | transpose k v | to md --center [v] --pretty
# => | k          |             v              |
# => | ---------- |:--------------------------:|
# => | version    |          0.104.2           |
# => | build_time | 2025-06-08 23:31:40 +02:00 |

Prefer OSC 9;9 on Windows over OSC 7 [toc]

@ofek made $env.config.shell_integration.osc7 = false by default on Windows in favor of $env.config.shell_integration.osc9_9 = true in #15914.

Disable expensive calculations with gstat --disable-tag [toc]

In #15893 did @snickerdoodle2 add the option --disable-tag to disable some of the heavy calculations of the gstat plugin.

Know what open and save can do with std/help [toc]

open and save can use from and to to convert data types. With the addition of @weirdan in #15651, the std/help command can now show these conversions.

Content type of view span [toc]

@weirdan added in #15842 a content type to view span. If your display hook highlights content types, will this be a nice addition.

Breaking changes [toc]

Cell-paths with case-sensitivity and without! [toc]

The new cell-path syntax !, introduced by @Bahex in #15692, may break some commands. If your commands relied on case-insensitive paths, please check your code.

Paths on lazy frames now produce expressions [toc]

Thanks to @ayax79 in #15891, paths on lazy frames now generate expressions. You will need to use polar collect to evaluate them.

Bug fixes and other changes [toc]

authortitlelink
@Bahexfix parsing of bare word string interpolations that start with a sub expression#15735
@Bahexfix: implicitly running .ps1 scripts with spaces in path#15781
@CSharperMantleCorrectly quote nu.exe and nu.ico path containing spaces in WiX#15881
@CSharperMantleFixup: Fix regression caused by #15881#15889
@Cattle0Horsefix(std/iter): align example descriptions with closure logic for find and find-index#15895
@LazyPlutofix: empty tables now respect $env.config.use_ansi_coloring (closes #14896)#15751
@Tyarel8fix duplicate short_name in ansi command#15767
@WindSoildersource: make sure the block is compiled when parsing#15798
@atahabakiNumbers proceeded with the escape character ignored fix#15684
@ayax79Fix for null handling #15788#15857
@blindFSfix(parser): namespace pollution of constants by use module.nu#15518
@blindFSfix: inefficient select with large row number#15730
@cableheadfix: clear jobs after traversing jobs for kill_all#15685
@cptpiepmatzAdd rustls for TLS#15810
@cptpiepmatzFix: use ring as a crypto provider instead of aws_lc#15812
@cptpiepmatzFix: Downgrade calamine to 0.26 to fix build without --locked#15908
@fdncredmake sure new nul chars don't print in char --list#15858
@fdncredmake date humanize use human_time_from_now()#15918
@hustcerFix Windows arm64 release binaries and winget related issues#15690
@hustcerFix build failure of aarch64 and armv7 musl targets#15835
@hustcerTry to fix PAT issue of winget publish account#15922
@jjflash95Fix #15571 panic on write to source parquet file#15601
@kamek-pffix(glob): Fix drive-letter glob expansion on Windows#15871
@kumarUjjawalfix(which): remove required positional argument to allow spread input#15870
@luismeyer95fix(parser): don't parse closure in block position (fixes #15417)#15680
@pyz4fix(polars): add Value::Record to NuExpression::can_downcast logic#15826
@pyz4fix(polars): swap out pivot for pivot_stable to suppress warning message#15913
@rritik772[FIX] #15813 passing infinity to random float generate causes error#15818
@ysthakurHandle multiple exact matches#15772
@zhiburtFix table wrap emojie#15138
@zhiburtnu-table/ 1 refactoring + a few optimizations + small fix#15653
@zhiburtFix #15653 regression with not counting padding properly#15704
@zhiburtnu-table: (table --expand) Remove unnecessary use of truncate logic#15727

Notes for plugin developers [toc]

Construct IoError from std::io::Error instead of std::io::ErrorKind [toc]

To give us better control over IO errors, @cptpiepmatz changed in #15777 how IoErrors are created. Now they’re built directly from std::io::Error instead of just the ErrorKind. Just remove the calls to .kind() and you're good to go.

Hall of fame [toc]

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

authortitlelink
@132iklUpdate where documentation#15467
@132iklPartial workaround and deprecation warning for breaking change usage of #15654#15806
@132iklDisable flaky killing_job_kills_pids test on macOS#15874
@Bahexrefactor Value::follow_cell_path to reduce clones and return Cow#15640
@BahexUpdate deprecation warnings#15867
@DoruminUpdate job_recv.rs#15673
@FlippinBergerCorrect use-facing to user-facing in CONTRIBUTING.md#15761
@KissakiAdd match examples for simple value and alternative values#15732
@LoicRiegelRemove legacy code in some core commands#15560
@LoicRiegelsmall refactoring around units and add tests#15746
@Tyarel8change http get header example to use a record#15674
@Tyarel8fix kv set examples#15769
@Villa01Improve error handling for unsupported --theme in to html command#15787
@ayax79Minor DataType refactor#15728
@ayax79Rust 1.85, edition=2024#15741
@ayax79Polars upgrade#15852
@ayax79Add regex documentation/examples to polars col#15898
@colececildocs: Add vfox to list of tools supporting Nushell#15687
@cptpiepmatzRefactor: Construct IoError from std::io::Error instead of std::io::ErrorKind#15777
@cptpiepmatzProvide a better error for prefix-only path for PWD#15817
@cptpiepmatzMove job errors into ShellError::Job variant#15820
@fdncredupdate nushell to use coreutils v0.1.0 crates#15896
@flovilmartfeat: Use reedline for input implementation#15369
@hackeryarnfeat: make to nuon raw option remove all white space#15609
@hustcerAdd a lightweight MSI packages release workflow for winget#15800
@hustcerUse nushell's fork for winget-pkgs publishing#15808
@hustcerBump dev version to 0.104.2#15809
@hustcerUpdate comments of release-pkg.nu for building of MSI package#15815
@hustcerAllow specifying MSI version via env var and workflow input#15828
@hustcerBump to 0.105.0#15930
@kumarUjjawalBetter error handling for negative integer exponents in ** operator#15882
@liquid-dragonsFix typo in examples of the table command#15925
@luong-komorebidocs: update ubuntu version in PLATFORM_SUPPORT.md#15662
@musicinmybrainUpdate lscolors from 0.17 to 0.20#15737
@new-years-eveRefactor find to handle regex search and non-regex search the same way#15839
@ofekFix typo in example config.nu#15910
@raoulkentreorder cals input_output_types#15909
@sholderbachClean public API of EngineState and friends#15636
@sholderbachPull reedline development version#15912
@tindzkdocs: fix available fields in history import command#15686
@vivainiostd-rfc/kv: optimize kv get by only selecting one row from the stor db#15792
@ysthakurBump to 0.104.1 dev version#15669
@ysthakurUse Default for making Suggestions in attribute_completions#15764

Full changelog [toc]

authortitlelink
@132iklUpdate where documentation#15467
@132iklAdd unified deprecation system and @deprecated attribute#15770
@132iklPartial workaround and deprecation warning for breaking change usage of #15654#15806
@132iklMake parse simple patterns ignore fields with placeholder (_)#15873
@132iklDisable flaky killing_job_kills_pids test on macOS#15874
@Bahexrefactor Value::follow_cell_path to reduce clones and return Cow#15640
@BahexAdd SyntaxShape::OneOf syntax users can use#15646
@Bahexfeat!: Explicit cell-path case sensitivity syntax#15692
@Bahexfeat(where): Support stored closure#15697
@Bahexfix parsing of bare word string interpolations that start with a sub expression#15735
@Bahexfix: implicitly running .ps1 scripts with spaces in path#15781
@Bahexfeat(std-rfc): add iter module and recurse command#15840
@BahexUpdate deprecation warnings#15867
@CSharperMantleCorrectly quote nu.exe and nu.ico path containing spaces in WiX#15881
@CSharperMantleFixup: Fix regression caused by #15881#15889
@Cattle0Horsefix(std/iter): align example descriptions with closure logic for find and find-index#15895
@DoruminUpdate job_recv.rs#15673
@FlippinBergerCorrect use-facing to user-facing in CONTRIBUTING.md#15761
@KissakiAdd match examples for simple value and alternative values#15732
@LazyPlutofix: empty tables now respect $env.config.use_ansi_coloring (closes #14896)#15751
@LoicRiegelRemove legacy code in some core commands#15560
@LoicRiegelsmall refactoring around units and add tests#15746
@MrfiregemAdd lazy closure evaluation to default (#14160)#15654
@MrfiregemAllow path join to read ByteStream input (#15128)#15736
@Mrfiregemrun-external spreads command if it's a list#15776
@Tyarel8change http get header example to use a record#15674
@Tyarel8fix duplicate short_name in ansi command#15767
@Tyarel8fix kv set examples#15769
@Tyarel8feat(std): add comparison support to bench command#15843
@Tyarel8feat(std): further bench improvements#15856
@Villa01Improve error handling for unsupported --theme in to html command#15787
@WindSoildersource: make sure the block is compiled when parsing#15798
@WindSoilderoverlay new: add --reload(-r) flag#15849
@app/dependabotbuild(deps): bump crate-ci/typos from 1.31.1 to 1.31.2#15665
@app/dependabotbuild(deps): bump actions-rust-lang/setup-rust-toolchain from 1.11.0 to 1.12.0#15666
@app/dependabotbuild(deps): bump miette from 7.5.0 to 7.6.0#15667
@app/dependabotbuild(deps): bump crate-ci/typos from 1.31.2 to 1.32.0#15708
@app/dependabotbuild(deps): bump tokio from 1.44.2 to 1.45.0#15710
@app/dependabotbuild(deps): bump quickcheck_macros from 1.0.0 to 1.1.0#15711
@app/dependabotbuild(deps): bump tempfile from 3.15.0 to 3.20.0#15753
@app/dependabotbuild(deps): bump crate-ci/typos from 1.32.0 to 1.33.1#15885
@app/dependabotbuild(deps): bump itertools from 0.13.0 to 0.14.0#15886
@atahabakiNumbers proceeded with the escape character ignored fix#15684
@ayax79Added polars struct-encode-json, providing the ability to encode structs as json#15678
@ayax79Minor DataType refactor#15728
@ayax79Rust 1.85, edition=2024#15741
@ayax79Polars upgrade#15852
@ayax79Allow polars first to be used with polars group-by#15855
@ayax79Fix for null handling #15788#15857
@ayax79Creates col and nth expressions when using paths on lazy frames.#15891
@ayax79Add regex documentation/examples to polars col#15898
@blindFSfix(parser): namespace pollution of constants by use module.nu#15518
@blindFSfix: inefficient select with large row number#15730
@cableheadfix: clear jobs after traversing jobs for kill_all#15685
@colececildocs: Add vfox to list of tools supporting Nushell#15687
@cptpiepmatzRefactor: Construct IoError from std::io::Error instead of std::io::ErrorKind#15777
@cptpiepmatzAdd rustls for TLS#15810
@cptpiepmatzFix: use ring as a crypto provider instead of aws_lc#15812
@cptpiepmatzProvide a better error for prefix-only path for PWD#15817
@cptpiepmatzMove job errors into ShellError::Job variant#15820
@cptpiepmatzAdd debug env command#15875
@cptpiepmatzFix: Downgrade calamine to 0.26 to fix build without --locked#15908
@fdncredallow powershell scripts in the path to be executed#15760
@fdncredmake sure new nul chars don't print in char --list#15858
@fdncredupdate nushell to use coreutils v0.1.0 crates#15896
@fdncredmake date humanize use human_time_from_now()#15918
@flovilmartfeat: Use reedline for input implementation#15369
@gmr458feat(table): Add new 'single' table mode#15672
@gmr458Add 'single' to supported table modes#15681
@hackeryarnfeat: make to nuon raw option remove all white space#15609
@hustcerFix Windows arm64 release binaries and winget related issues#15690
@hustcerAdd a lightweight MSI packages release workflow for winget#15800
@hustcerUse nushell's fork for winget-pkgs publishing#15808
@hustcerBump dev version to 0.104.2#15809
@hustcerUpdate comments of release-pkg.nu for building of MSI package#15815
@hustcerAllow specifying MSI version via env var and workflow input#15828
@hustcerFix build failure of aarch64 and armv7 musl targets#15835
@hustcerTry to fix PAT issue of winget publish account#15922
@hustcerBump to 0.105.0#15930
@jjflash95Fix #15571 panic on write to source parquet file#15601
@kamek-pffix(glob): Fix drive-letter glob expansion on Windows#15871
@kumarUjjawalfix(which): remove required positional argument to allow spread input#15870
@kumarUjjawalBetter error handling for negative integer exponents in ** operator#15882
@lazengafeat(to-md): add support for centering columns via CellPaths (#14552)#15861
@liquid-dragonsFix typo in examples of the table command#15925
@luismeyer95fix(parser): don't parse closure in block position (fixes #15417)#15680
@luong-komorebidocs: update ubuntu version in PLATFORM_SUPPORT.md#15662
@musicinmybrainUpdate lscolors from 0.17 to 0.20#15737
@new-years-eveRefactor find to handle regex search and non-regex search the same way#15839
@noahfraiturefeat: default http protocol when none used in http request#15804
@ofekFix typo in example config.nu#15910
@ofekEnable shell_integration.osc9_9 by default on Windows#15914
@pyz4feat(polars): add polars horizontal aggregation command#15656
@pyz4feat(polars): introducing new polars replace#15706
@pyz4feat(polars): expand polars unique to allow expressions inputs#15771
@pyz4feat(polars): add polars math expression#15822
@pyz4fix(polars): add Value::Record to NuExpression::can_downcast logic#15826
@pyz4feat(polars): expand polars shift to allow expressions inputs#15834
@pyz4feat(polars): add maintain-order flag to polars group-by and allow expression inputs in polars filter#15865
@pyz4fix(polars): swap out pivot for pivot_stable to suppress warning message#15913
@raoulkentreorder cals input_output_types#15909
@rritik772[FIX] #15813 passing infinity to random float generate causes error#15818
@sholderbachClean public API of EngineState and friends#15636
@sholderbachPull reedline development version#15912
@snickerdoodle2(gstat): add config option to disable tag calculation#15893
@tindzkdocs: fix available fields in history import command#15686
@vivainiostd-rfc/kv: optimize kv get by only selecting one row from the stor db#15792
@weirdanEnvironment-aware help for open and save#15651
@weirdanSet content_type for view span output#15842
@ysthakurBump to 0.104.1 dev version#15669
@ysthakurUse Default for making Suggestions in attribute_completions#15764
@ysthakurHandle multiple exact matches#15772
@zhiburtFix table wrap emojie#15138
@zhiburtnu-table/ 1 refactoring + a few optimizations + small fix#15653
@zhiburtFix #15653 regression with not counting padding properly#15704
@zhiburtnu-table: (table --expand) Remove unnecessary use of truncate logic#15727
Edit this page on GitHub
Contributors: Piepmatz