Bun Shell (Bun.$) is a built-in shell that lets you write cross-platform shell scripts in TypeScript. No child_process. No exec. Just template literals.
Basic Usage: Shell as Template Literals
import { $ } from "bun";
// Run any command
await $`echo Hello, World!`;
// Get output as text
const result = await $`ls -la`.text();
console.log(result);
// Get as JSON
const pkg = await $`cat package.json`.json();
console.log(pkg.name);
// Get as lines
const files = await $`find . -name "*.ts"`.lines();
Variables: Safe Interpolation
const dir = "/tmp/my-project";
const branch = "main";
// Variables are automatically escaped — NO injection!
await $`mkdir -p ${dir}`;
await $`git clone --branch ${branch} https://github.com/user/repo.git ${dir}`;
// Arrays become multiple arguments
const files = ["file1.ts", "file2.ts", "file3.ts"];
await $`prettier --write ${files}`;
Pipes and Redirects
// Pipe between commands
await $`cat data.csv | grep "error" | wc -l`;
// Redirect to file
await $`echo "hello" > output.txt`;
await $`echo "world" >> output.txt`;
// Pipe to Bun APIs
const response = await fetch("https://api.example.com/data");
await $`jq '.items[]' < ${response}`;
Error Handling
import { $ } from "bun";
// Throws on non-zero exit
try {
await $`exit 1`;
} catch (e) {
console.log(e.exitCode); // 1
console.log(e.stderr.toString());
}
// Quiet mode — don't print to stdout
const result = await $`ls -la`.quiet();
// Nothrow — don't throw on error
const r = await $`command-that-might-fail`.nothrow();
if (r.exitCode !== 0) console.log("Failed, but continuing...");
Environment Variables
await $`NODE_ENV=production bun run build`;
// Or set for all commands
$.env({ NODE_ENV: "production", API_KEY: "secret" });
await $`bun run build`;
Real-World: Build Scripts
#!/usr/bin/env bun
import { $ } from "bun";
// Build pipeline
console.log("Building...");
await $`bun run typecheck`;
await $`bun build ./src/index.ts --outdir ./dist --minify`;
// Run tests
const testResult = await $`bun test`.nothrow();
if (testResult.exitCode !== 0) {
console.error("Tests failed!");
process.exit(1);
}
// Deploy
const version = await $`git describe --tags`.text();
await $`docker build -t myapp:${version.trim()} .`;
await $`docker push myapp:${version.trim()}`;
console.log("Deployed version:", version.trim());
Bun APIs: Beyond Shell
// File I/O — fastest in JS
const file = Bun.file("data.json");
const data = await file.json();
await Bun.write("output.csv", csvData);
// HTTP server
Bun.serve({
port: 3000,
fetch(req) {
return new Response("Hello!");
},
});
// SQLite — built-in
import { Database } from "bun:sqlite";
const db = new Database("scraping.db");
db.run("CREATE TABLE IF NOT EXISTS results (url TEXT, data TEXT)");
Build scraping scripts with Bun? My Apify tools handle the heavy lifting.
Custom Bun-powered solution? Email spinov001@gmail.com
Top comments (0)