Skip to content

API Reference

$.sync

Zx provides both synchronous and asynchronous command executions, returns ProcessOutput or ProcessPromise respectively.

js
const list = await $`ls -la`
const dir = $.sync`pwd`

$({...})

$ object holds the default zx configuration, which is used for all execution. To specify a custom preset use $ as factory:

js
const $$ = $({
  verbose: false,
  env: {NODE_ENV: 'production'},
})

const env = await $$`node -e 'console.log(process.env.NODE_ENV)'`
const pwd = $$.sync`pwd`
const hello = $({quiet: true})`echo "Hello!"`

Moreover, presets are chainable:

js
const $1 = $({ nothrow: true })
assert.equal((await $1`exit 1`).exitCode, 1)

const $2 = $1({ sync: true }) // Both {nothrow: true, sync: true} are applied
assert.equal($2`exit 2`.exitCode, 2)

const $3 = $({ sync: true })({ nothrow: true })
assert.equal($3`exit 3`.exitCode, 3)

$({input})

The input option passes the specified stdin to the command.

js
const p1 = $({ input: 'foo' })`cat`
const p2 = $({ input: Readable.from('bar') })`cat`
const p3 = $({ input: Buffer.from('baz') })`cat`
const p4 = $({ input: p3 })`cat`
const p5 = $({ input: await p3 })`cat`

$({signal})

The signal option makes the process abortable.

js
const {signal} = new AbortController()
const p = $({ signal })`sleep 9999`

setTimeout(() => signal.abort('reason'), 1000)

$({timeout})

The timeout option makes the process autokillable after the specified delay.

js
const p = $({timeout: '1s'})`sleep 999`

The full options list:

ts
interface Options {
  cwd:            string
  ac:             AbortController
  signal:         AbortSignal
  input:          string | Buffer | Readable | ProcessOutput | ProcessPromise
  timeout:        Duration
  timeoutSignal:  string
  stdio:          StdioOptions
  verbose:        boolean
  sync:           boolean
  env:            NodeJS.ProcessEnv
  shell:          string | boolean
  nothrow:        boolean
  prefix:         string
  postfix:        string
  quote:          typeof quote
  quiet:          boolean
  detached:       boolean
  spawn:          typeof spawn
  spawnSync:      typeof spawnSync
  log:            typeof log
  kill:           typeof kill
}

cd()

Changes the current working directory.

js
cd('/tmp')
await $`pwd` // => /tmp

Like echo, in addition to string arguments, cd accepts and trims trailing newlines from ProcessOutput enabling common idioms like:

js
cd(await $`mktemp -d`)

⚠️ cd invokes process.chdir() internally, so it does affect the global context. To keep process.cwd() in sync with separate $ calls enable syncProcessCwd() hook.

fetch()

A wrapper around the node-fetch-native package.

js
const resp = await fetch('https://medv.io')

question()

A wrapper around the readline package.

js
const bear = await question('What kind of bear is best? ')

sleep()

A wrapper around the setTimeout function.

js
await sleep(1000)

echo()

A console.log() alternative which can take ProcessOutput.

js
const branch = await $`git branch --show-current`

echo`Current branch is ${branch}.`
// or
echo('Current branch is', branch)

stdin()

Returns the stdin as a string.

js
const content = JSON.parse(await stdin())

within()

Creates a new async context.

js
await $`pwd` // => /home/path
$.foo = 'bar'

within(async () => {
  $.cwd = '/tmp'
  $.foo = 'baz'

  setTimeout(async () => {
    await $`pwd` // => /tmp
    $.foo // baz
  }, 1000)
})

await $`pwd` // => /home/path
$.foo // still 'bar'
js
await $`node --version` // => v20.2.0

const version = await within(async () => {
  $.prefix += 'export NVM_DIR=$HOME/.nvm; source $NVM_DIR/nvm.sh; nvm use 16;'

  return $`node --version`
})

echo(version) // => v16.20.0

syncProcessCwd()

Keeps the process.cwd() in sync with the internal $ current working directory if it is changed via cd().

ts
import {syncProcessCwd} from 'zx'

syncProcessCwd()
syncProcessCwd(false) // pass false to disable the hook

This feature is disabled by default because of performance overhead.

retry()

Retries a callback for a few times. Will return after the first successful attempt, or will throw after specifies attempts count.

js
const p = await retry(10, () => $`curl https://medv.io`)

// With a specified delay between attempts.
const p = await retry(20, '1s', () => $`curl https://medv.io`)

// With an exponential backoff.
const p = await retry(30, expBackoff(), () => $`curl https://medv.io`)

spinner()

Starts a simple CLI spinner.

js
await spinner(() => $`long-running command`)

// With a message.
await spinner('working...', () => $`sleep 99`)

glob()

The globby package.

js
const packages = await glob(['package.json', 'packages/*/package.json'])

which()

The which package.

js
const node = await which('node')

If nothrow option is used, returns null if not found.

js
const pathOrNull = await which('node', { nothrow: true })

ps()

The @webpod/ps package to provide a cross-platform way to list processes.

js
const all = await ps.lookup()
const nodejs = await ps.lookup({ command: 'node' })
const children = await ps.tree({ pid: 123 })
const fulltree = await ps.tree({ pid: 123, recursive: true })

kill()

A process killer.

js
await kill(123)
await kill(123, 'SIGKILL')

tmpdir()

Creates a temporary directory.

js
t1 = tmpdir()       // /os/based/tmp/zx-1ra1iofojgg/
t2 = tmpdir('foo')  // /os/based/tmp/zx-1ra1iofojgg/foo/

tmpfile()

Temp file factory.

js
f1 = tmpfile()         // /os/based/tmp/zx-1ra1iofojgg
f2 = tmpfile('f.txt')  // /os/based/tmp/zx-1ra1iofojgg/foo.txt
f3 = tmpfile('f.txt', 'string or buffer')

minimist

The minimist package.

js
const argv = minimist(process.argv.slice(2), {})

argv

A minimist-parsed version of the process.argv as argv.

js
if (argv.someFlag) {
  echo('yes')
}

Use minimist options to customize the parsing:

js
const myCustomArgv = minimist(process.argv.slice(2), {
  boolean: [
    'force',
    'help',
  ],
  alias: {
    h: 'help',
  },
})

chalk

The chalk package.

js
console.log(chalk.blue('Hello world!'))

fs

The fs-extra package.

js
const {version} = await fs.readJson('./package.json')

os

The os package.

js
await $`cd ${os.homedir()} && mkdir example`

path

The path package.

js
await $`mkdir ${path.join(basedir, 'output')}`

yaml

The yaml package.

js
console.log(YAML.parse('foo: bar').foo)

Disclaimer: This is not an officially supported Google product.