Quick Start
Get up and running with Xec in just 5 minutes. This guide covers installation, basic usage, and your first multi-environment command.
Installation
Install the CLI
npm install -g @xec-sh/cli
Or use npx without installation:
npx @xec-sh/cli --help
Install the Core Library
For use in Node.js projects:
npm install @xec-sh/core
Your First Command
Using the CLI
Xec provides built-in commands for multi-environment execution:
# Execute locally
xec run -e "console.log('Hello, Xec!')"
# Execute on SSH host
xec on user@server.com "uptime"
# Execute in Docker container
xec in my-container "npm test"
# Copy files between environments
xec copy local.txt server.com:/remote/path/
Execute a Script
echo "await $\`echo 'Hello from script'\`" > hello.js
xec run hello.js
Using the Library
Create a file example.js:
import { $ } from '@xec-sh/core';
// Execute locally
const greeting = await $`echo "Hello, Xec!"`.text();
console.log(greeting); // "Hello, Xec!"
// Get system information
const info = await $`uname -a`.text();
console.log(info);
Run it:
node example.js
Working with Different Environments
SSH Execution
Connect to a remote server:
import { $ } from '@xec-sh/core';
// String shorthand: [user@]host[:port]
const server = $.ssh('user@example.com');
// Or with full options — the programmatic API uses 'username'
// (YAML target config uses 'user' instead)
const serverWithKey = $.ssh({
host: 'example.com',
username: 'user',
privateKey: '~/.ssh/id_rsa'
});
const uptime = await server`uptime`.text();
console.log(`Server uptime: ${uptime}`);
Docker Execution
Run commands in containers:
import { $ } from '@xec-sh/core';
// Use existing container
await $.docker({ container: 'my-app' })`npm test`;
// Create ephemeral container with configuration
await $.docker({
image: 'node:20',
autoRemove: true,
volumes: ['./src:/app'],
workdir: '/app'
})`npm install && npm run build`;
// Or use fluent API
await $.docker()
.ephemeral('node:20')
.volumes(['./src:/app'])
.workdir('/app')
.run('npm install && npm run build');
Kubernetes Execution
Execute in pods:
import { $ } from '@xec-sh/core';
// Execute command in pod
const hostname = await $.k8s({
pod: 'web-server',
namespace: 'default'
})`hostname`.text();
console.log(`Pod hostname: ${hostname}`);
// Get logs from pod (kubectl runs locally, not inside the pod)
const logs = await $`kubectl logs web-server -n default --tail=100`.text();
console.log(logs);
Common Patterns
Error Handling
// Continue on error
const result = await $`exit 1`.nothrow();
if (!result.ok) {
console.log(`Failed with: ${result.cause}`);
}
// With timeout
try {
await $`sleep 60`.timeout(5000);
} catch (error) {
console.log('Command timed out');
}
Working with Output
// Get text output (trimmed stdout)
const text = await $`cat file.txt`.text();
// Parse JSON
const data = await $`cat config.json`.json();
// Process lines (empty lines dropped)
const files = await $`ls -1`.lines();
files.forEach(file => console.log(file));
Method Chaining
await $`npm test`
.cd('/app') // Set working directory
.env({ NODE_ENV: 'test' }) // Set environment
.timeout(30000) // Set timeout
.quiet() // Suppress output
.nothrow(); // Don't throw on error
Parallel Execution
// Run commands in parallel
const results = await $.parallel.all([
$`npm test`,
$`npm run lint`,
$`npm run type-check`
]);
// Run with concurrency limit
const serverCommands = servers.map(s =>
$.ssh({ host: s })`apt update`
);
const results2 = await $.parallel.all(serverCommands, {
concurrency: 3
});
Interactive REPL Mode
Start an interactive REPL with Xec pre-loaded:
xec run --repl
# Now in REPL with $ available
> await $`ls -la`
> const files = await $`find . -name "*.js"`.lines()
> files.length
Interactive Command Mode
Many commands support interactive mode for guided execution:
# Interactive file copy
xec copy --interactive
# Interactive port forwarding
xec forward --interactive
# Interactive command execution
xec on --interactive
Project Configuration
Create .xec/config.yaml for project-specific settings:
defaults:
timeout: 30000
shell: /bin/bash
targets:
hosts:
prod:
type: ssh
host: prod.example.com
user: deploy # YAML targets use 'user' (the programmatic $.ssh() API uses 'username')
privateKey: ~/.ssh/deploy_key
containers:
staging:
type: docker
container: staging-app
tasks:
deploy:
description: Deploy to production
command: |
git pull &&
npm install &&
npm run build &&
pm2 restart app
targets: [hosts.prod]
Run configured tasks:
xec run deploy
Creating Custom Commands
Create .xec/commands/greet.js:
export function command(program) {
program
.command('greet <name>')
.description('Greet someone')
.action(async (name) => {
const { $ } = await import('@xec-sh/core');
await $`echo "Hello, ${name}!"`;
await $`date`;
});
}
Use your custom command:
xec greet World
What's Next?
Now that you've seen the basics:
- Explore the Philosophy - Understand the design principles behind Xec
- Learn When to Use Xec - See real-world use cases
- Dive into Examples - Check out comprehensive examples
- Read the Configuration Guide - Explore configuration options
Getting Help
- Documentation: docs.xec.sh
- GitHub: github.com/xec-sh/xec
- Discord: discord.gg/xec
Tips for Success
- Start simple - Begin with local execution before moving to remote environments
- Use TypeScript - Get full IntelliSense and type checking
- Handle errors - Always consider failure cases with
.nothrow()or try/catch - Monitor execution - Use the event system for debugging
- Use parallel execution - Leverage
$.parallel.all()for concurrent operations