Skip to content

API Reference

Alpha

@catapultjs/deploy is currently in alpha. Its API may change between minor releases until it reaches a stable version. Pin the package version in your package.json to avoid unexpected breaking changes during updates.

All functions are exported from @catapultjs/deploy.

Enums (PackageManager, Verbose) are available from a dedicated entry point:

typescript
import { PackageManager, Verbose } from '@catapultjs/deploy/enums'

Configuration

defineConfig(config)

Initialises the deployment configuration. Must be used as the default export of your deploy.ts.

typescript
export default defineConfig({
  keepReleases: 5,
  hosts: [
    {
      name: 'production',
      ssh: 'deploy@example.com',
      deployPath: '/home/deploy/myapp',
      branch: 'main',
    },
  ],
})

Options

OptionTypeDescription
hostsHost[]List of servers to deploy to
keepReleases?numberNumber of releases to keep (default: 5)
repository?stringGit repository URL (auto-detected from origin)
packageManager?PackageManagerPackage manager used by pm(), pmInstall(), pmInstallProd() (auto-detected from lock files, defaults to PackageManager.NPM)
hooks?HooksLifecycle hooks (beforeDeploy, afterDeploy, …)
verbose?VerboseVerbosity level: Verbose.SILENT nothing, Verbose.NORMAL shows task progress, Verbose.TRACE also prints SSH commands, Verbose.DEBUG also streams stdout (default: Verbose.TRACE)

Host options

OptionTypeDescription
namestringHost identifier
sshstring | SshConfigSSH connection string or object
deployPathstringAbsolute path on the server
branch?string | BranchWithPromptBranch to deploy
healthcheck?HealthcheckHealthcheck configuration
bin?Record<string, string>Per-host binary path overrides

SshConfig options

OptionTypeDescription
userstringSSH user
hoststringSSH host
port?numberSSH port (default: 22)
typescript
ssh: { user: 'deploy', host: 'example.com', port: 2222 }

BranchWithPrompt options

OptionTypeDescription
namestringDefault branch name
askbooleanPrompt the user to enter a branch name, with name as the default value
typescript
branch: { name: 'develop', ask: true }

Healthcheck options

OptionTypeDescription
url?stringURL to check after deployment
retries?numberNumber of attempts before failing
delayMs?numberDelay between retries in ms (default: 3000)
typescript
healthcheck: {
  url: 'http://127.0.0.1:3333/health',
  retries: 10,
  delayMs: 3000,
}

bin options

Map of binary name to absolute path on the server. Used by bin() to resolve the correct executable per host.

typescript
bin: {
  node: '/home/deploy/.nvm/versions/node/v22/bin/node',
  npm: '/home/deploy/.nvm/versions/node/v22/bin/npm',
}

Task DSL

These functions are used inside task callbacks to build the SSH command sequence.

desc(description)

Sets a description for the next task() call. Used by cata list:tasks to display a description column. Optional.

typescript
import { desc, task, cd, run } from '@catapultjs/deploy'

desc('Builds the application assets')
task('my:build', () => {
  cd('{{release_path}}')
  run('npm run build')
})

task(name, fn)

Registers a task. If a task with the same name already exists, it is replaced.

typescript
import { task, cd, run } from '@catapultjs/deploy'

task('my:build', () => {
  cd('{{release_path}}')
  run('npm ci')
  run('npm run build')
})

The callback receives a TaskContext as its first argument:

typescript
task('my:build', async ({ host, paths, config, release, logger }) => {
  // ...
})

TaskContext fields

FieldTypeDescription
hostHostThe host being deployed to
pathsPathsResolved server paths
configConfigThe resolved deploy configuration
releasestringThe release name (e.g. 2024-01-15T10-30-00-000Z)
loggerLoggerLogger instance for output

Paths fields

FieldValue
base{deployPath}
current{deployPath}/current
releases{deployPath}/releases
release{deployPath}/releases/{release}
shared{deployPath}/shared
cataConfig{deployPath}/.catapult
repo{deployPath}/.catapult/repo
lock{deployPath}/.catapult/deploy.lock

cd(path)

Sets the working directory for subsequent run() calls. Supports template variables.

typescript
cd('{{release_path}}')

Must be called inside a task callback.


run(command)

Queues a shell command to run on the server. Supports template variables. All queued commands are sent in a single SSH session at the end of the task, prefixed with set -e.

typescript
run('npm ci')
run('npm run build')

Must be called inside a task callback.


bin(name)

Resolves a binary path. Checks the current host's bin config first, then falls back to the binary name.

typescript
task('my:build', () => {
  cd('{{release_path}}')
  run(`${bin('node')} my-script.js`)
})

Per-host binary paths are configured in defineConfig:

typescript
{
  name: 'production',
  ssh: 'deploy@example.com',
  deployPath: '/home/deploy/myapp',
  bin: {
    node: '/home/deploy/.nvm/versions/node/v22/bin/node',
  },
}

local(command, options?)

Executes a shell command on the local machine. Flushes any queued run() commands first. Prints the command at Verbose.TRACE level and streams stdout at Verbose.DEBUG level.

OptionTypeDescription
cwd?stringWorking directory for the command (defaults to process.cwd())
typescript
task('my:task', async () => {
  await local('npm run build')
  await local('npm run test', { cwd: './frontend' })
  await upload('./dist/.', '{{release_path}}/dist')
})

Must be called inside an async task callback.


upload(localPath, remotePath)

Uploads a local file or directory to the remote server via SCP. Flushes any queued run() commands first. Supports template variables in remotePath. If remotePath is relative, it is resolved against host.deployPath.

typescript
task('my:task', async () => {
  await upload('./dist/app.zip', '{{release_path}}/app.zip')
})

Must be called inside an async task callback.


download(remotePath, localPath)

Downloads a file or directory from the remote server via SCP. Flushes any queued run() commands first. Supports template variables in remotePath. If remotePath is relative, it is resolved against host.deployPath.

typescript
task('my:task', async () => {
  await download('{{release_path}}/config.json', './config.json')
})

Must be called inside an async task callback.


isVerbose(level)

Returns true if the current verbosity is at least level. Useful for conditional logging inside async tasks.

typescript
import { task, isVerbose } from '@catapultjs/deploy'
import { Verbose } from '@catapultjs/deploy/enums'

task('my:task', async ({ host, logger }) => {
  if (isVerbose(Verbose.NORMAL)) logger.step(host.name, 'doing something')
  if (isVerbose(Verbose.TRACE)) logger.cmd('my-command --flag')
})

Pipeline

getPipeline()

Returns a copy of the current pipeline as an array of task names.

typescript
const pipeline = getPipeline()
// ['deploy:lock', 'deploy:release', ...]

setPipeline(tasks)

Replaces the entire pipeline.

typescript
setPipeline([
  'deploy:release',
  'deploy:update_code',
  'deploy:shared',
  'deploy:publish',
  'deploy:unlock',
  'deploy:cleanup',
])

before(existing, newTask)

Inserts newTask immediately before existing in the pipeline. Throws if existing is not found.

typescript
before('deploy:publish', 'my:task')

after(existing, newTask)

Inserts newTask immediately after existing in the pipeline. Throws if existing is not found.

typescript
after('deploy:publish', 'my:task')

remove(name)

Removes a task from the pipeline. Throws if the task is not found.

typescript
remove('deploy:log_revision')

inPipeline(name)

Returns true if the task is present in the current pipeline.

typescript
if (inPipeline('deploy:healthcheck')) {
  after('deploy:healthcheck', 'notify')
} else {
  after('deploy:publish', 'notify')
}

onSetup(fn)

Registers a callback to run during cata deploy:setup, after the base directories are created. Useful for creating shared directories or files specific to your application.

typescript
import { onSetup } from '@catapultjs/deploy'
import { ssh, q, getPaths } from '@catapultjs/deploy/utils'

onSetup(async (ctx, host, logger) => {
  const paths = getPaths(host.deployPath, ctx.release)
  await ssh(host, `mkdir -p ${q(paths.shared + '/uploads')}`)
  logger.step(host.name, 'uploads directory ready')
})

onStatus(fn)

Registers a callback to run during cata status. Useful for displaying additional information such as a process manager version or queue state.

typescript
import { onStatus } from '@catapultjs/deploy'
import { ssh } from '@catapultjs/deploy/utils'

onStatus(async (_ctx, host, logger) => {
  const { stdout } = await ssh(host, `set +e\nmy-service --version || true`)
  logger.log(`my-service ${stdout.trim() || 'unavailable'}`)
})

Store

Key/value store for sharing configuration between deploy.ts and recipes.

Core keys

KeyTypeDefaultUsed by
shared_dirsstring[][]deploy:shared
shared_filesstring[][]deploy:shared, deploy:setup
writable_dirsstring[][]deploy:setup

Recipe keys

KeyTypeDefaultUsed by
adonisjs_pathstring''recipes/adonisjs
astro_modestring | Record<string, string>'production'recipes/astro
directus_pathstring''recipes/directus
directus_snapshot_pathstring'./snapshot.yaml'recipes/directus
nuxt_pathstring''recipes/nuxt
redis_dbnumber | number[]1recipes/redis
source_pathstringdepends reciperecipes/astro, recipes/rsync
rsync_source_pathstring./recipes/rsync
rsync_excludesstring[][]recipes/rsync
vitepress_pathstring''recipes/vitepress

set(key, value)

Stores a value under the given key.

typescript
import { set } from '@catapultjs/deploy'

set('shared_dirs', ['storage', 'logs'])

get(key, defaultValue?)

Retrieves a value from the store. Returns defaultValue if the key is not set.

typescript
import { get } from '@catapultjs/deploy'

const dirs = get<string[]>('shared_dirs', [])

has(key)

Returns true if the key is set.

typescript
import { has } from '@catapultjs/deploy'

if (has('source_path')) {
  // ...
}

Package manager

pm()

Returns the current package manager binary. Reads packageManager from defineConfig, defaults to npm.

typescript
run(`${pm()} run build`)

pmInstall()

Returns the install command with frozen lockfile for the current package manager.

packageManagerCommand
npmnpm ci
pnpmpnpm install --frozen-lockfile
yarnyarn install --frozen-lockfile
bunbun ci
typescript
run(pmInstall())

pmInstallProd()

Returns the production-only install command for the current package manager.

packageManagerCommand
npmnpm ci --omit=dev
pnpmpnpm install --frozen-lockfile --prod
yarnyarn install --frozen-lockfile --production
bunbun ci --omit=dev
typescript
run(pmInstallProd())

Template variables

Available in cd() and run():

VariableValue
{{release_path}}/base/releases/<release>
{{current_path}}/base/current
{{shared_path}}/base/shared
{{releases_path}}/base/releases
{{base_path}}/base
{{release}}Release name (e.g. 2024-01-15T10-30-00-000Z)