Zap makes remote and container development feel just like local development. It automatically syncs your files and runs commands remotely, so you don’t have to juggle ssh and rsync.
Use the zap
command to sync local directories, run scripts, and manage services on a remote host.
Zap also supports SSH mode, where it uses --host ssh://user@host
to push files and execute commands over SSH directly—no Zap server needs to be running on the remote side.
Zap will pick the interpreter based on file extension:
# Python scripts
zap run script.py # invokes python3 script.py
# JavaScript files
zap run script.js # invokes node script.js
# TypeScript files (requires ts-node installed locally or globally)
zap run script.ts # invokes ts-node script.ts
# NPM scripts (fallback)
zap run my-script # invokes npm run my-script
If your project’s
package.json
includes azap:pre
script, Zap will run it automatically before invoking your main script.
# One-time sync of the current directory
zap --host user@host sync
# Sync then execute locally-defined script
zap --host user@host sync run script.py
# Continuously sync and restart on changes
zap --host user@host --sync exec npm start
# Direct remote execution of an arbitrary shell command as a service
zap --host user@host --exec 'ls -a ./dist'
# List services
zap --host user@host list
# Detailed help
zap --help
Zap can load configuration from these sources, in order (first wins):
-
CLI flags (e.g.
--host
,--key
,--config
) -
Environment variables or a
.env
file (e.g.ZAP_HOST
,ZAP_HOSTS
,ZAP_KEY
,ZAP_SYNC
,ZAP_IGNORE
, etc.) -
zapconfig.json
file in the working directory -
zap
field inpackage.json
For example, add a
zap
section to yourpackage.json
:{ "zap": { "host": "myhost", "key": "<api-token>", "sync": true, "ignore": ["node_modules", "dist"] } }
You can also define named hosts mapping in your
zap
config or via theZAP_HOSTS
environment variable:{ "zap": { "hosts": { "hostA": "ssh://user@somehost.local", "hostB": "token@host-server.local:5000" } } }
Or in your shell or
.env
file:export ZAP_HOSTS="hostA:ssh://user@somehost.local,hostB:token@host-server.local:5000"
Follow these steps to run the Zap host server:
-
Install dependencies:
npm install
-
Create a
.env
file in the project root and set required environment variables:ZAP_TOKEN=<your_api_token> ZAP_SECRET=<your_jwt_secret> ZAP_PORT=<optional_port (default: 3000)>
-
Start the host server:
npm run host -- [--token <token>] [--username <user>] [--password <pass>] [--secret <secret>] [--port <port>]
You can also use
npm run host
and rely on values in.env
.
Use the Zap CLI to interact with the host server:
-
Install the CLI globally (optional):
npm install -g .
-
Or use
npx
without a global install:npx zap --host <host_address> [options] <command> [args...]
-
Common commands:
# Sync current directory to the remote host zap --host user@host sync # Run a command on the remote host after syncing zap --host user@host sync run npm start # Continuously sync while running a remote command zap --host user@host --sync exec npm start # List services zap --host user@host list
For full details on commands and options, run:
zap --help
Follow these steps to launch Zap via Docker:
-
Ensure Docker and Docker Compose v2 are installed.
-
Create a
.env
file with at leastZAP_TOKEN
andZAP_SECRET
:ZAP_TOKEN=<your_api_token> ZAP_SECRET=<your_jwt_secret>
-
Start the containers:
docker compose -f docker-compose.yml -p zap-host up --build -d
-
To stop and remove the containers:
docker compose -f docker-compose.yml -p zap-host down
If you need arbitrary extra mounts (e.g. host folders or data volumes), use a Compose override file:
-
Create
docker-compose.override.yml
alongside basedocker-composese.yml
:version: '3.9' services: server: volumes: - /path/on/host/foo:/mydata/foo - /mnt/datasets:/mydata/data/datasets
-
Launch with both files so that your overrides are merged:
docker compose \ -f docker-compose.yml \ -f docker-compose.override.yml \ up -d