You pipe JSON from an API into `grep`, then `cut`, then `awk`, and the script breaks the day a field moves. Nushell skips the text parsing. Every command hands the next one a table, a list, or a record, so you filter and sort by column name instead of by character position. This guide covers the 20% of Nushell that does 80% of the work: tables and pipelines, opening data files, records and lists, finding help, variables, custom commands with `def`, and your configuration file. A searchable command reference and a curated set of videos, podcasts, books, and online resources close the article. ## What You'll Learn * When Nushell is the right tool, and when bash or zsh still fits better. * How tables flow through a pipeline, so `where`, `select`, and `sort-by` make sense. * How to open JSON, CSV, and TOML files and convert between formats. * How records and lists work, and how to read a field. * How to find help, store values in variables, and write your own commands. * How to find and change your Nushell configuration. ## When to Use Nushell Nushell (often called nu) is a cross-platform shell that treats output as structured data. If you want the background on why it exists, read [What Is Nushell?][what-is-nushell] first. This guide sticks to the commands. ### What Nushell Does Well * Exploring JSON, CSV, TOML, and YAML files without a separate tool for each format. * Filtering and sorting command output by column, such as files by size. * Writing small scripts with typed parameters and clear error messages. * Working the same way on Linux, macOS, and Windows. ### Where Nushell Is Not the Right Tool * Running existing bash scripts. Nushell is not POSIX compatible, so `.sh` files still need bash. * Pasting one-liners from bash tutorials. Syntax such as `$(...)`, `&&` chains, and `export VAR=value` differs. * Shared team scripts, when the rest of the team doesn't run Nushell. Install Nushell with your package manager, then run `nu` to start it: ```bash # macOS brew install nushell # Windows winget install nushell # Any platform with Rust installed cargo install nu --locked ``` The examples below use a small practice file, `servers.json`, holding five servers with a name, region, status, and CPU percentage. The [Practice Nushell](#practice-nushell) section shows how to create it in your own terminal. ## Tables and Pipelines Most Nushell commands return a table. Open the practice file and you see rows and named columns instead of raw text: ```nu open servers.json ``` ```text ╭───┬──────────┬────────────┬─────────┬─────╮ │ # │ name │ region │ status │ cpu │ ├───┼──────────┼────────────┼─────────┼─────┤ │ 0 │ web-01 │ us-west │ running │ 42 │ │ 1 │ web-02 │ us-west │ stopped │ 0 │ │ 2 │ db-01 │ us-east │ running │ 71 │ │ 3 │ cache-01 │ eu-central │ running │ 18 │ │ 4 │ batch-01 │ us-east │ stopped │ 0 │ ╰───┴──────────┴────────────┴─────────┴─────╯ ``` The pipe `|` passes that table to the next command. Use `where` to keep matching rows and `select` to keep only the columns you need: ```nu open servers.json | where status == "running" | select name cpu ``` ```text ╭───┬──────────┬─────╮ │ # │ name │ cpu │ ├───┼──────────┼─────┤ │ 0 │ web-01 │ 42 │ │ 1 │ db-01 │ 71 │ │ 2 │ cache-01 │ 18 │ ╰───┴──────────┴─────╯ ``` Sort by any column with `sort-by`, and take the top rows with `first`: ```nu open servers.json | sort-by cpu --reverse | first 2 ``` ```text ╭───┬────────┬─────────┬─────────┬─────╮ │ # │ name │ region │ status │ cpu │ ├───┼────────┼─────────┼─────────┼─────┤ │ 0 │ db-01 │ us-east │ running │ 71 │ │ 1 │ web-01 │ us-west │ running │ 42 │ ╰───┴────────┴─────────┴─────────┴─────╯ ``` Built-in commands work the same way. `ls` returns a table of files, so you filter it by size with no `awk` in sight: ```nu ls | where size > 4kb | get name ``` ```text ╭───┬────────────╮ │ 0 │ access.log │ ╰───┴────────────╯ ``` **What you get:** one habit, `command | where ... | select ...`, that works on files, processes, and data files alike. ## Open Data Files `open` reads a file and parses it by its extension. JSON, CSV, TOML, YAML, and more come back as tables and records: ```nu open app.toml | get server.port ``` ```text 8080 ``` ```nu open app.toml | get log.level ``` ```text info ``` CSV files open as tables too, so the same commands apply: ```nu open sales.csv | first 3 ``` ```text ╭───┬────────────┬────────────┬─────────┬───────┬────────╮ │ # │ date │ region │ product │ units │ amount │ ├───┼────────────┼────────────┼─────────┼───────┼────────┤ │ 0 │ 2026-03-01 │ us-west │ gadget │ 19 │ 228.00 │ │ 1 │ 2026-03-01 │ us-east │ widget │ 35 │ 665.00 │ │ 2 │ 2026-03-02 │ eu-central │ gizmo │ 36 │ 684.00 │ ╰───┴────────────┴────────────┴─────────┴───────┴────────╯ ``` Count rows with `length`: ```nu open sales.csv | where region == "eu-central" | length ``` ```text 20 ``` Group rows by a column with `group-by`. The result is a record keyed by the column's values, so `columns` lists the groups: ```nu open servers.json | group-by region | columns ``` ```text ╭───┬────────────╮ │ 0 │ us-west │ │ 1 │ us-east │ │ 2 │ eu-central │ ╰───┴────────────╯ ``` Reduce a column to one number with the `math` commands: ```nu open sales.csv | get units | math sum ``` ```text 1317 ``` ```nu open servers.json | get cpu | math max ``` ```text 71 ``` Files that Nushell doesn't recognize, such as a log, open as text. Split text into a list of lines with `lines`: ```nu open access.log | lines | first 2 ``` ```text ╭───┬──────────────────────────────────────────────────────────────────────────╮ │ 0 │ 10.0.0.222 - - [09/Jan/2026:08:00:00 +0000] "GET /api/servers HTTP/1.1" │ │ │ 500 5534 │ │ 1 │ 10.0.0.156 - - [09/Jan/2026:08:00:01 +0000] "GET /api/sales HTTP/1.1" │ │ │ 500 4982 │ ╰───┴──────────────────────────────────────────────────────────────────────────╯ ``` A list of lines works with the same commands as any other list. Count the lines, then count the requests that got a 404: ```nu open access.log | lines | length ``` ```text 190 ``` ```nu open access.log | lines | where $it =~ " 404 " | length ``` ```text 17 ``` Add `--raw` to skip parsing and get the file's text, even for a format Nushell knows, such as Markdown: ```nu open --raw notes.md | lines | first ``` ```text # Practice notes ``` Convert between formats with the `to` commands, and write the result with `save`: ```nu open servers.json | where status == "stopped" | to csv ``` ```text name,region,status,cpu web-02,us-west,stopped,0 batch-01,us-east,stopped,0 ``` ```nu open servers.json | where status == "running" | save --force running.json ``` `save` picks the format from the file extension, so `running.json` gets JSON. `--force` replaces the file if it already exists. The `from` commands go the other way: they parse text you already have, such as the body of a web response, into a table or record. If you know jq, `where status == "running"` does the job of jq's `select(.status == "running")`. The [Learn jq cookbook][learn-jq] shows the jq side of the same structured-data ideas. ## Records and Lists A table is a list of records. A record is a set of named fields in braces, and a list is values in square brackets. Read a field with a dot: ```nu let server = {name: "web-01", region: "us-west", cpu: 42} $server.cpu ``` ```text 42 ``` ```nu let regions = [us-west us-east eu-central] $regions | length ``` ```text 3 ``` `get` pulls one column out of a table as a list, or one row out as a record: ```nu open servers.json | get name ``` ```text ╭───┬──────────╮ │ 0 │ web-01 │ │ 1 │ web-02 │ │ 2 │ db-01 │ │ 3 │ cache-01 │ │ 4 │ batch-01 │ ╰───┴──────────╯ ``` When a command does something unexpected, ask what kind of value you have with `describe`: ```nu let server = {name: "web-01", region: "us-west", cpu: 42} $server | describe ``` ```text record ``` ## Get Help Nushell documents itself. Run `help` with a command name to see its description, flags, and examples: ```nu help where ``` `help commands` lists every command as a table, so you search it with the same `where` you use on data: ```nu help commands | where name =~ "sort" | get name ``` ```text ╭───┬─────────╮ │ 0 │ sort │ │ 1 │ sort-by │ ╰───┴─────────╯ ``` `help --find csv` searches command descriptions as well as names, which helps when you know what you want to do but not the command's name. ## Variables `let` creates a variable you can't change. `mut` creates one you can. Prefix a variable with `$` to read it: ```nu mut total = 0 for s in (open servers.json) { $total += $s.cpu } $total ``` ```text 131 ``` Use a variable anywhere a value fits, such as a filter: ```nu let threshold = 40 open servers.json | where cpu > $threshold | length ``` ```text 2 ``` Reach for `let` first. Most of the time a pipeline gives you the value directly, and `mut` is only needed for loops like the one above. ## Write Your Own Commands `def` defines a command. Parameters can carry a type and a default value, and the command behaves like a built-in one, help text included: ```nu def busy [threshold: int = 40] { open servers.json | where cpu > $threshold | get name } busy busy 60 ``` ```text ╭───┬───────╮ │ 0 │ db-01 │ ╰───┴───────╯ ``` `busy` with no argument uses the default of 40 and lists `web-01` and `db-01`. `busy 60` lists only `db-01`, as shown. Commands you define at the prompt last until you close the shell. Put them in your configuration file to keep them. ## Configure Nushell Nushell keeps its configuration in `config.nu`. Print its location with `$nu.config-path`, and open it in your editor with `config nu`: ```nu $nu.config-path ``` The practice shell prints this path. On your machine, it starts with your own home directory: ```text /home/reader/.config/nushell/config.nu ``` Settings live in the `$env.config` record. Change one for the current session by assigning to it: ```nu $env.config.table.mode = "light" open servers.json | first 2 ``` ```text # name region status cpu ────────────────────────────────────── 0 web-01 us-west running 42 1 web-02 us-west stopped 0 ``` To keep a setting, run `config nu` and add the same line, `$env.config.table.mode = "light"`, to the end of `config.nu`. Changes to `config.nu` apply to new sessions. Run `nu` to start a fresh session inside the current one, check the change, then run `exit` to return. ## Practice Nushell Nushell sticks once you type it. A practice shell that runs real Nushell in this page is on its way to this section. Until it arrives, run the drill below in your own terminal. It takes about ten minutes. First, create the practice file in an empty directory. This one command builds a table from literal rows and saves it as JSON, unless the file is already there: ```nu if not ("servers.json" | path exists) { [[name region status cpu]; [web-01 us-west running 42] [web-02 us-west stopped 0] [db-01 us-east running 71] [cache-01 eu-central running 18] [batch-01 us-east stopped 0]] | save servers.json } ``` Then work through these steps: 1. Run `open servers.json` and read the table. 2. List the stopped servers with `where status == "stopped"`. 3. Show only the `name` and `region` columns of the running servers. 4. Sort the servers by `cpu`, highest first, and keep the top three. 5. Count the servers in `us-east`. 6. Convert the running servers to CSV with `to csv`. 7. Define a command named `in-region` that takes a region and lists the server names in it, then run `in-region eu-central`. ## Command Reference Verified with Nushell 0.116.0. Search the reference to find a command fast. Each entry shows the command, then what it does. ### Filter and Shape Tables * *where status == "running"* - Keep the rows that match a condition * *where cpu > 40* - Keep the rows where a number column is above a value * *select name cpu* - Keep only the named columns * *get name* - Pull one column out of a table as a list * *sort-by cpu* - Sort rows by a column, lowest first * *sort-by cpu --reverse* - Sort rows by a column, highest first * *first 2* - Keep the first rows of a table or list * *length* - Count the rows of a table or the items of a list * *group-by region* - Group rows into a record keyed by a column's values * *columns* - List the column names of a table ### Files and Formats * *open servers.json* - Read a file and parse it by its extension * *open access.log | lines* - Read a text file as a list of lines * *ls* - List the files in the current directory as a table * *save running.json* - Write the pipeline's value to a file, in the format the extension names * *save --append notes.md* - Add the pipeline's value to the end of a file * *to csv* - Convert a table to CSV text * *to json* - Convert a value to JSON text * *to nuon* - Convert a value to NUON, Nushell's own data format * *from json* - Parse JSON text into a table or record * *from csv* - Parse CSV text into a table ### Records, Lists, and Types * *{name: "web-01", cpu: 42}* - Create a record with named fields * *[3 1 2]* - Create a list of values * *$server.cpu* - Read a field from a record * *$regions | length* - Count the items in a list * *describe* - Show the type of a value ### Help * *help where* - Show a command's description, flags, and examples * *help commands* - List every command as a table you can filter * *help --find csv* - Search command names and descriptions for a word ### Variables and Commands * *let name = value* - Create a variable you can't change * *mut total = 0* - Create a variable you can change * *def busy [threshold: int = 40] { ... }* - Define a command with a typed parameter and a default ### Configuration * *$nu.config-path* - Print the path of your config.nu file * *config nu* - Open config.nu in your editor * *$env.config* - The record that holds every setting * *$env.config.table.mode = "light"* - Change a setting for the current session ### Examples Each example runs on the practice file and shows what Nushell prints. ```nu open servers.json | where region == "us-east" | get name ``` ```text ╭───┬──────────╮ │ 0 │ db-01 │ │ 1 │ batch-01 │ ╰───┴──────────╯ ``` ```nu open servers.json | first | to nuon ``` ```text {name: "web-01", region: us-west, status: running, cpu: 42} ``` ```nu open servers.json | group-by status ``` ```text ╭─────────┬────────────────╮ │ running │ [table 3 rows] │ │ stopped │ [table 2 rows] │ ╰─────────┴────────────────╯ ``` ## Plugins and Networking Nushell fetches web data with `http get`, and the response arrives already parsed. This example needs a network connection: ```nu http get https://api.github.com/repos/nushell/nushell | get stargazers_count # runs on your machine ``` Plugins add commands written in Rust or other languages. The Polars plugin adds fast dataframe commands for large CSV and Parquet files. Install it with Cargo, then register it with Nushell: ```bash cargo install nu_plugin_polars --locked ``` ```nu plugin add ~/.cargo/bin/nu_plugin_polars # runs on your machine plugin use polars # runs on your machine ``` Run external programs as you would in any shell. When an external program shares a name with a Nushell command, prefix it with `^` to run the program instead: ```nu ^git status # runs on your machine ``` ## Learn Nushell: Beyond the Basics With pipelines, data files, and a custom command or two in hand, these resources take you further. Start with a video, then keep the Nushell Book open while you write your first scripts. ### Video * [NuShell: A New Type of Shell][video-better-stack] by Better Stack, a short introduction to structured pipelines. * [Nushell in a Nutshell][video-dj-ware] by DJ Ware, a beginner-oriented overview of the shell and its commands. * [Nushell for Beginners: A Better Linux Shell Than Bash?][video-ojamboshop] by ojamboshop, a first look aimed at bash users. * [How to Create Custom CLIs for Internal Developer Platforms with Nushell][video-devops-toolkit] by DevOps & AI Toolkit, a longer walkthrough that builds real tools with `def`. ### Audio and Podcasts * [Nushell for the GitHub era][podcast-changelog] on The Changelog, with creators Jonathan Turner, Andrés N. Robalino, and Yehuda Katz on why they built it. * [How to build a Nushell][podcast-shipit] on Ship It!, with core maintainers Devyn Cairns and Jakub Žádník on building a cross-platform shell. * [Nushell with WindSoilder][podcast-rustacean] on Rustacean Station, a conversation with a Nushell contributor about the project's Rust internals. ### Books * [The Nushell Book][nushell-book], the free official guide from the Nushell team, from first commands to modules and scripts. * [Mastering Nushell: Modern Shell Scripting and Data Automation for Engineers and Analysts][book-mastering] by Philip Oscar, a book-length treatment of scripting and data automation. ### Online * [Coming from Bash][coming-from-bash], the official table that maps bash commands to their Nushell equivalents. * [Thinking in Nu][thinking-in-nu], the official page on the habits that trip up newcomers. * [The Nushell command reference][nushell-commands], every built-in command with its flags and examples. * [The Nushell Cookbook][nushell-cookbook], task-focused recipes for files, tables, and HTTP. * [awesome-nu][awesome-nu], a curated list of Nushell plugins, scripts, and tools. ## Related Content * [What Is Nushell?][what-is-nushell] explains why a shell built on structured data exists and when it fits. * [Learn jq][learn-jq] covers the JSON filter many people use before they try Nushell. * [jq vs. yq][jq-vs-yq] compares two single-format tools that Nushell's `open` command replaces for many tasks. * [Learn Tmux][learn-tmux] pairs with Nushell: run nu in one pane and your editor in another. [video-better-stack]: https://www.youtube.com/watch?v=nbbVJGNxnic [video-dj-ware]: https://www.youtube.com/watch?v=bv7LbrgT2qA [video-ojamboshop]: https://www.youtube.com/watch?v=ZUfgiuGqhLI [video-devops-toolkit]: https://www.youtube.com/watch?v=TgQZz2kGysk [podcast-changelog]: https://changelog.com/podcast/363 [podcast-shipit]: https://changelog.com/shipit/109 [podcast-rustacean]: https://rustacean-station.org/episode/windsoilder/ [nushell-book]: https://www.nushell.sh/book/ [book-mastering]: https://www.amazon.com/dp/B0G1X6BR6J [coming-from-bash]: https://www.nushell.sh/book/coming_from_bash.html [thinking-in-nu]: https://www.nushell.sh/book/thinking_in_nu.html [nushell-commands]: https://www.nushell.sh/commands/ [nushell-cookbook]: https://www.nushell.sh/cookbook/ [awesome-nu]: https://github.com/nushell/awesome-nu [what-is-nushell]: https://jeffbailey.us/blog/2026/01/08/what-is-nushell/ [learn-jq]: https://jeffbailey.us/blog/2021/11/30/learn-jq/ [jq-vs-yq]: https://jeffbailey.us/blog/2026/09/20/jq-vs-yq/ [learn-tmux]: https://jeffbailey.us/blog/2026/09/27/learn-tmux/