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:
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.
export default defineConfig({
keepReleases: 5,
hosts: [
{
name: 'production',
ssh: 'deploy@example.com',
deployPath: '/home/deploy/myapp',
branch: 'main',
},
],
})Options
| Option | Type | Description |
|---|---|---|
hosts | Host[] | List of servers to deploy to |
keepReleases? | number | Number of releases to keep (default: 5) |
repository? | string | Git repository URL (auto-detected from origin) |
packageManager? | PackageManager | Package manager used by pm(), pmInstall(), pmInstallProd() (auto-detected from lock files, defaults to PackageManager.NPM) |
hooks? | Hooks | Lifecycle hooks (beforeDeploy, afterDeploy, …) |
verbose? | Verbose | Verbosity 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
| Option | Type | Description |
|---|---|---|
name | string | Host identifier |
ssh | string | SshConfig | SSH connection string or object |
deployPath | string | Absolute path on the server |
branch? | string | BranchWithPrompt | Branch to deploy |
healthcheck? | Healthcheck | Healthcheck configuration |
bin? | Record<string, string> | Per-host binary path overrides |
SshConfig options
| Option | Type | Description |
|---|---|---|
user | string | SSH user |
host | string | SSH host |
port? | number | SSH port (default: 22) |
ssh: { user: 'deploy', host: 'example.com', port: 2222 }BranchWithPrompt options
| Option | Type | Description |
|---|---|---|
name | string | Default branch name |
ask | boolean | Prompt the user to enter a branch name, with name as the default value |
branch: { name: 'develop', ask: true }Healthcheck options
| Option | Type | Description |
|---|---|---|
url? | string | URL to check after deployment |
retries? | number | Number of attempts before failing |
delayMs? | number | Delay between retries in ms (default: 3000) |
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.
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.
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.
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:
task('my:build', async ({ host, paths, config, release, logger }) => {
// ...
})TaskContext fields
| Field | Type | Description |
|---|---|---|
host | Host | The host being deployed to |
paths | Paths | Resolved server paths |
config | Config | The resolved deploy configuration |
release | string | The release name (e.g. 2024-01-15T10-30-00-000Z) |
logger | Logger | Logger instance for output |
Paths fields
| Field | Value |
|---|---|
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.
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.
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.
task('my:build', () => {
cd('{{release_path}}')
run(`${bin('node')} my-script.js`)
})Per-host binary paths are configured in defineConfig:
{
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.
| Option | Type | Description |
|---|---|---|
cwd? | string | Working directory for the command (defaults to process.cwd()) |
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.
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.
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.
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.
const pipeline = getPipeline()
// ['deploy:lock', 'deploy:release', ...]setPipeline(tasks)
Replaces the entire pipeline.
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.
before('deploy:publish', 'my:task')after(existing, newTask)
Inserts newTask immediately after existing in the pipeline. Throws if existing is not found.
after('deploy:publish', 'my:task')remove(name)
Removes a task from the pipeline. Throws if the task is not found.
remove('deploy:log_revision')inPipeline(name)
Returns true if the task is present in the current pipeline.
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.
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.
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
| Key | Type | Default | Used by |
|---|---|---|---|
shared_dirs | string[] | [] | deploy:shared |
shared_files | string[] | [] | deploy:shared, deploy:setup |
writable_dirs | string[] | [] | deploy:setup |
Recipe keys
| Key | Type | Default | Used by |
|---|---|---|---|
adonisjs_path | string | '' | recipes/adonisjs |
astro_mode | string | Record<string, string> | 'production' | recipes/astro |
directus_path | string | '' | recipes/directus |
directus_snapshot_path | string | './snapshot.yaml' | recipes/directus |
nuxt_path | string | '' | recipes/nuxt |
redis_db | number | number[] | 1 | recipes/redis |
source_path | string | depends recipe | recipes/astro, recipes/rsync |
rsync_source_path | string | ./ | recipes/rsync |
rsync_excludes | string[] | [] | recipes/rsync |
vitepress_path | string | '' | recipes/vitepress |
set(key, value)
Stores a value under the given key.
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.
import { get } from '@catapultjs/deploy'
const dirs = get<string[]>('shared_dirs', [])has(key)
Returns true if the key is set.
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.
run(`${pm()} run build`)pmInstall()
Returns the install command with frozen lockfile for the current package manager.
packageManager | Command |
|---|---|
npm | npm ci |
pnpm | pnpm install --frozen-lockfile |
yarn | yarn install --frozen-lockfile |
bun | bun ci |
run(pmInstall())pmInstallProd()
Returns the production-only install command for the current package manager.
packageManager | Command |
|---|---|
npm | npm ci --omit=dev |
pnpm | pnpm install --frozen-lockfile --prod |
yarn | yarn install --frozen-lockfile --production |
bun | bun ci --omit=dev |
run(pmInstallProd())Template variables
Available in cd() and run():
| Variable | Value |
|---|---|
{{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) |