TL;DR:
- Nushell is a modern shell where commands return structured data (tables, records, lists) rather than raw text, letting you filter and transform output without reaching for awk, sed, or jq.
- It runs on Linux, macOS, and Windows, installs in minutes, and works alongside your existing shell — you don’t have to switch your default shell to try it.
- The steeper learning curve is real: Nushell’s scripting syntax differs from bash, and some assumptions (like “everything is text”) don’t hold. It rewards the investment for heavy terminal users.
Bash has been the default shell for most developers for decades. It’s powerful, ubiquitous, and deeply embedded in muscle memory. It’s also, frankly, awkward to use. Parsing command output means piping through awk '{print $3}' or grep -oP '(?<=key=)\w+' expressions that are genuinely hard to write correctly. JSON from API calls goes through jq. CSVs need special handling. Getting the fifth column from a command that outputs a table requires counting spaces.
Nushell takes a different approach: commands return structured data, not strings. When you run ls in Nushell, you get a table with typed columns — name, size, modified, permissions — that you can query like a database. When you call an API, the JSON comes back as a native record. This isn’t a cosmetic difference. It changes how you work.
The Core Idea: Structured Pipelines
In bash, ls -la | awk '{print $5, $9}' extracts columns from text by position. In Nushell:
ls | select name size
ls returns a table. select picks columns by name. The output is still a table. This composes:
ls | where size > 1mb | sort-by size --reverse | first 10
Find files larger than 1MB, sort by size descending, show the top 10. No awk, no sort flags to memorise, no head.
With system processes:
ps | where cpu > 5 | sort-by cpu --reverse
With HTTP APIs:
http get https://api.github.com/repos/nushell/nushell/releases
| first
| select tag_name published_at
The JSON response becomes a table directly. No jq '.[] | {tag: .tag_name, date: .published_at}'.
Getting Started
Install via your package manager:
# macOS
brew install nushell
# Windows
winget install Nushell.Nushell
# Linux (via cargo)
cargo install nu
# Or download from https://www.nushell.sh
Run nu to start a Nushell session. Your existing PATH works. Most external commands work fine — Nushell calls them as subprocesses and captures their text output, which you can still parse if needed.
Working With Data
Nushell has built-in support for several data formats:
# Parse CSV
open data.csv | where revenue > 10000
# Parse JSON
open config.json | get database.host
# Parse TOML
open Cargo.toml | get package.version
# Parse YAML
open docker-compose.yml | get services | columns
The open command detects the format and returns structured data. get navigates nested structures using dot notation.
Combining data sources:
# Join two tables
let users = open users.csv
let orders = open orders.json
$users | join $orders id
String parsing when you need it:
# Split and process text output
git log --oneline -20
| lines
| each { |line| $line | split column ' ' hash message }
| flatten
lines splits text into a list. each maps over items. split column parses each line into structured columns.
Practical Recipes
Find the largest node_modules in your projects:
ls ~/projects | where type == dir | each { |d|
let size = (du $d.name | get physical | first)
{project: $d.name, size: $size}
} | sort-by size --reverse | first 5
Check which ports are listening:
ss -tlnp | detect columns | where port | sort-by port
Parse git log into a table:
git log --format="%h|%an|%s" -20
| lines
| split column "|" hash author message
Summarise HTTP response times from a log file:
open access.log
| lines
| parse '{ip} - - [{date}] "{method} {path} HTTP/{ver}" {status} {bytes} "{ref}" "{ua}" {time}'
| select path status time
| update time { |r| $r.time | into float }
| group-by status
| each { |g| { status: $g.name, avg_time: ($g.items.time | math avg) } }
Scripting in Nushell
Nushell scripts use .nu extensions. The scripting syntax is clean but differs from bash — variables use $ prefix, functions use def, and there’s no implicit string concatenation:
# script.nu
def greet [name: string, --formal(-f)] {
if $formal {
$"Good day, ($name)."
} else {
$"Hey ($name)!"
}
}
greet "Alice" # Hey Alice!
greet --formal "Alice" # Good day, Alice.
Type annotations in function signatures catch errors before they happen — a significant improvement over bash’s “everything is a string” model.
Configuration
Nushell stores config in ~/.config/nushell/config.nu. Common customisations:
# config.nu
# Prompt customisation
$env.PROMPT_COMMAND = {|| $"(ansi green)(whoami)(ansi reset)@(hostname) (ansi cyan)(pwd)(ansi reset) > " }
# Aliases
alias ll = ls -la
alias gs = git status
# Environment variables
$env.EDITOR = "nvim"
# Load starship prompt
mkdir ~/.cache/starship
starship init nu | save -f ~/.cache/starship/init.nu
use ~/.cache/starship/init.nu
Nushell works well with Starship prompt for cross-shell consistency.
The Honest Trade-offs
Nushell requires learning a new scripting model. Bash scripts don’t run in Nushell directly — you need to rewrite them, or call them explicitly with bash script.sh. The initial mental shift from “text in, text out” to “data in, data out” takes time.
Some commands produce text that Nushell can’t automatically structure — older tools, custom scripts, anything that doesn’t follow parseable patterns. For these, you’re still in text-processing territory.
And the ecosystem is smaller than bash. StackOverflow has thirty years of bash answers; Nushell’s community is active but younger.
That said, for developers who spend significant time in the terminal processing command output, working with JSON APIs, or writing automation scripts, Nushell’s structured data model genuinely reduces friction. The common data manipulation tasks that require awk expertise in bash become readable one-liners. That’s a real productivity gain.
The best way to try it: install Nushell, run nu inside your current terminal session, and spend an afternoon with it. You don’t have to change your default shell — just see whether the structured approach clicks.