@actions/exec provides cross-platform command execution utilities specifically designed for GitHub Actions. It enables reliable execution of CLI tools and processes with streaming output, captured results, and robust error handling across different operating systems.
npm install @actions/execimport { exec, getExecOutput } from "@actions/exec";
import type { ExecOptions, ExecOutput, ExecListeners } from "@actions/exec";
import type { Writable } from "stream";For CommonJS:
const { exec, getExecOutput } = require("@actions/exec");import { exec, getExecOutput } from "@actions/exec";
// Execute command with streaming output to console
const exitCode = await exec("node", ["--version"]);
// Execute command and capture output
const result = await getExecOutput("git", ["status", "--porcelain"]);
console.log(result.stdout); // captured stdout
console.log(result.stderr); // captured stderr
console.log(result.exitCode); // exit code
// Execute with options
const options = {
cwd: "./src",
env: { NODE_ENV: "development" },
silent: true
};
await exec("npm", ["test"], options);Execute commands with real-time output streaming to the console and return the exit code.
/**
* Exec a command.
* Output will be streamed to the live console.
* Returns promise with return code
*
* @param commandLine - command to execute (can include additional args). Must be correctly escaped.
* @param args - optional arguments for tool. Escaping is handled by the lib.
* @param options - optional exec options. See ExecOptions
* @returns Promise<number> - exit code
*/
function exec(
commandLine: string,
args?: string[],
options?: ExecOptions
): Promise<number>;Usage Examples:
// Simple command execution
await exec("echo", ["Hello World"]);
// Command with working directory
await exec("npm", ["install"], { cwd: "./project" });
// Command with environment variables
await exec("node", ["script.js"], {
env: { NODE_ENV: "production" }
});
// Command with custom output streams
import * as fs from "fs";
const logStream = fs.createWriteStream("output.log");
await exec("npm", ["test"], {
outStream: logStream,
errStream: logStream
});Execute commands and capture both streaming output and final stdout/stderr results.
/**
* Exec a command and get the output.
* Output will be streamed to the live console.
* Returns promise with the exit code and collected stdout and stderr
*
* @param commandLine - command to execute (can include additional args). Must be correctly escaped.
* @param args - optional arguments for tool. Escaping is handled by the lib.
* @param options - optional exec options. See ExecOptions
* @returns Promise<ExecOutput> - exit code, stdout, and stderr
*/
function getExecOutput(
commandLine: string,
args?: string[],
options?: ExecOptions
): Promise<ExecOutput>;Usage Examples:
// Capture command output
const result = await getExecOutput("git", ["log", "--oneline", "-n", "5"]);
if (result.exitCode === 0) {
const commitLines = result.stdout.trim().split("\n");
console.log(`Found ${commitLines.length} recent commits`);
}
// Handle errors from captured output
const testResult = await getExecOutput("npm", ["test"], { ignoreReturnCode: true });
if (testResult.exitCode !== 0) {
console.error("Tests failed:", testResult.stderr);
}
// Capture with custom listeners for real-time processing
let lineCount = 0;
const result = await getExecOutput("find", ["/", "-name", "*.log"], {
listeners: {
stdline: (line) => {
lineCount++;
if (lineCount % 100 === 0) {
console.log(`Processed ${lineCount} lines...`);
}
}
}
});Configuration options for command execution.
interface ExecOptions {
/** optional working directory. defaults to current */
cwd?: string;
/** optional envvar dictionary. defaults to current process's env */
env?: {[key: string]: string};
/** optional. defaults to false */
silent?: boolean;
/** optional out stream to use. Defaults to process.stdout */
outStream?: Writable;
/** optional err stream to use. Defaults to process.stderr */
errStream?: Writable;
/** optional. whether to skip quoting/escaping arguments if needed. defaults to false. */
windowsVerbatimArguments?: boolean;
/** optional. whether to fail if output to stderr. defaults to false */
failOnStdErr?: boolean;
/** optional. defaults to failing on non zero. ignore will not fail leaving it up to the caller */
ignoreReturnCode?: boolean;
/** optional. How long in ms to wait for STDIO streams to close after the exit event of the process before terminating. defaults to 10000 */
delay?: number;
/** optional. input to write to the process on STDIN. */
input?: Buffer;
/** optional. Listeners for output. Callback functions that will be called on these events */
listeners?: ExecListeners;
}Result object returned by getExecOutput function.
interface ExecOutput {
/** The exit code of the process */
exitCode: number;
/** The entire stdout of the process as a string */
stdout: string;
/** The entire stderr of the process as a string */
stderr: string;
}Event listeners for real-time output processing during command execution.
interface ExecListeners {
/** A call back for each buffer of stdout */
stdout?: (data: Buffer) => void;
/** A call back for each buffer of stderr */
stderr?: (data: Buffer) => void;
/** A call back for each line of stdout */
stdline?: (data: string) => void;
/** A call back for each line of stderr */
errline?: (data: string) => void;
/** A call back for each debug log */
debug?: (data: string) => void;
}The @actions/exec library provides comprehensive error handling:
Error for null/empty commandLine parameterError if specified cwd does not existError with process error detailsError by default (configurable via ignoreReturnCode)failOnStdErr)Error Handling Examples:
try {
// This will throw if the command fails
await exec("nonexistent-command");
} catch (error) {
console.error("Command failed:", error.message);
}
// Ignore return codes and handle manually
const result = await getExecOutput("grep", ["pattern", "file.txt"], {
ignoreReturnCode: true
});
if (result.exitCode !== 0) {
console.log("Pattern not found, but continuing...");
}
// Fail on any stderr output
try {
await exec("command-that-warns", [], { failOnStdErr: true });
} catch (error) {
console.error("Command produced stderr output:", error.message);
}@actions/exec provides full cross-platform support:
Platform-Specific Examples:
// Cross-platform file listing
if (process.platform === "win32") {
await exec("dir", ["/b"]);
} else {
await exec("ls", ["-1"]);
}
// Windows verbatim arguments (skip escaping)
await exec("cmd", ["/c", "echo", "Hello & World"], {
windowsVerbatimArguments: true
});
// Cross-platform shell commands
const isWindows = process.platform === "win32";
const shell = isWindows ? "cmd" : "sh";
const shellFlag = isWindows ? "/c" : "-c";
await exec(shell, [shellFlag, "echo $HOME || echo %USERPROFILE%"]);