I’ve moved most of my small scripts to Bun. It sidesteps Windows’ lack of shebang support and the Git-for-Windows/WSL bash dance, and gives you one runtime for both ad-hoc shell-style commands and full scripts.
Problems Bun solves
Windows doesn’t execute #!/usr/bin/env python3 or #!/bin/bash, so scripts written for Linux or macOS usually need a separate PowerShell version. Bun compiles JavaScript to native executables, so a single script can run cross-platform without shebangs.
Mise file tasks have started to support shebangs on Windows in the latest release, but they rely on system bash.exe, which often points at WSL. Bun does not. You run bun ./script.js and embed shell commands via Bun.$; the script uses Bun’s bundled bash environment.
Why Bun for shell scripts
The command bun build ./script.ts --compile --outfile script produces a single binary, so no shebang or interpreter is needed on Windows. The Bun.build API is available too; I use a build.js script to walk a directory and compile all executables. Pre-built binaries start quickly—Bun’s docs cite ~5ms vs Node’s ~25ms for a simple script, which helps for small, frequently run scripts.
Bun has strong support for shell-style scripting. Bun Shell runs bash commands; the main entry point is Bun.$, which constructs shell commands from template literals for safe interpolation, similar to google/zx. On Windows, Bun ships with MSYS, so you get a consistent bash environment and common Linux CLI tools without extra setup.
Other useful features:
Bun.secrets—Securely store and retrieve secrets using the OS keystore (Windows Credential Manager, macOS Keychain, Linux libsecret). Secrets - Bun- Built-in support for glob patterns, YAML parsing, ANSI colors, and more. Bun Runtime
Short example
import { $ } from "bun";
const out = await $`echo hello`.text();
console.log(out); // hello
Run it with bun run script.js or bun ./script.js.