{"id":19355483,"url":"https://github.com/tinylibs/tinyexec","last_synced_at":"2026-05-23T18:01:05.434Z","repository":{"id":246764252,"uuid":"789836769","full_name":"tinylibs/tinyexec","owner":"tinylibs","description":"📟 A tiny, higher level interface around child_process","archived":false,"fork":false,"pushed_at":"2026-05-19T09:26:31.000Z","size":358,"stargazers_count":359,"open_issues_count":9,"forks_count":19,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-05-19T10:12:42.863Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinylibs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["43081j"]}},"created_at":"2024-04-21T17:28:02.000Z","updated_at":"2026-05-19T09:26:34.000Z","dependencies_parsed_at":null,"dependency_job_id":"da964a14-30f7-46a1-8a1b-de4fb4022c12","html_url":"https://github.com/tinylibs/tinyexec","commit_stats":null,"previous_names":["tinylibs/tinyexec"],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/tinylibs/tinyexec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyexec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyexec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyexec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyexec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinylibs","download_url":"https://codeload.github.com/tinylibs/tinyexec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyexec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33318027,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T12:23:38.849Z","status":"ssl_error","status_checked_at":"2026-05-21T12:22:11.673Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T06:01:13.039Z","updated_at":"2026-05-23T18:01:05.428Z","avatar_url":"https://github.com/tinylibs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/43081j"],"categories":["TypeScript","Utilities"],"sub_categories":["Process Execution"],"readme":"# tinyexec 📟\n\n\u003e A minimal package for executing commands\n\nThis package was created to provide a minimal way of interacting with child\nprocesses without having to manually deal with streams, piping, etc.\n\n## Installing\n\n```sh\n$ npm i -S tinyexec\n```\n\n## Usage\n\nA process can be spawned and awaited like so:\n\n```ts\nimport {x} from 'tinyexec';\n\nconst result = await x('ls', ['-l']);\n\n// result.stdout - the stdout as a string\n// result.stderr - the stderr as a string\n// result.exitCode - the process exit code as a number\n```\n\nBy default, tinyexec does not throw on non‑zero exit codes. Check `result.exitCode` or pass `{throwOnError: true}`.\n\nOutput is returned exactly as produced; trailing newlines are not trimmed. If you need trimming, do it explicitly:\n\n```ts\nconst clean = result.stdout.replace(/\\r?\\n$/, '');\n```\n\nYou may also iterate over the lines of output via an async loop:\n\n```ts\nimport {x} from 'tinyexec';\n\nconst proc = x('ls', ['-l']);\n\nfor await (const line of proc) {\n  // line will be from stderr/stdout in the order you'd see it in a term\n}\n```\n\n### Options\n\nOptions can be passed to have finer control over spawning of the process:\n\n```ts\nawait x('ls', [], {\n  timeout: 1000\n});\n```\n\nThe options object can have the following properties:\n\n- `signal` - an `AbortSignal` to allow aborting of the execution\n- `timeout` - time in milliseconds at which the process will be forcibly killed\n- `persist` - if `true`, the process will continue after the host exits\n- `stdin` - `string` or another `Result` that will be used as the input to the process\n- `nodeOptions` - any valid options to node's underlying `spawn` function\n- `throwOnError` - if true, non-zero exit codes will throw an error\n- `nodePath` - if `false`, `node_modules/.bin` directories and the current node executable's directory will not be prepended to `PATH` (defaults to `true`)\n\n### Passing a string to stdin\n\nYou can pass a string to `stdin`, which is useful for whitespace-sensitive values and for secrets that shouldn’t be exposed in shell history:\n\n```ts\nconst result = await x('gh', ['auth', 'login', '--with-token'], {\n  stdin: process.env.GITHUB_TOKEN\n});\n\nconsole.log(result.exitCode);\n```\n\n### Piping to another process\n\nYou can pipe a process to another via the `pipe` method:\n\n```ts\nconst proc1 = x('ls', ['-l']);\nconst proc2 = proc1.pipe('grep', ['.js']);\nconst result = await proc2;\n\nconsole.log(result.stdout);\n```\n\n`pipe` takes the same options as a regular execution. For example, you can\npass a timeout to the pipe call:\n\n```ts\nproc1.pipe('grep', ['.js'], {\n  timeout: 2000\n});\n```\n\n### Killing a process\n\nYou can kill the process via the `kill` method:\n\n```ts\nconst proc = x('ls');\n\nproc.kill();\n\n// or with a signal\nproc.kill('SIGHUP');\n```\n\n### Node modules/binaries\n\nBy default, node's available binaries from `node_modules` will be accessible\nin your command.\n\nFor example, in a repo which has `eslint` installed:\n\n```ts\nawait x('eslint', ['.']);\n```\n\nIn this example, `eslint` will come from the locally installed `node_modules`.\n\nIf you'd rather not have `node_modules/.bin` (or the directory of the current\n`node` executable) prepended to `PATH`, pass `nodePath: false`:\n\n```ts\nawait x('eslint', ['.'], {nodePath: false});\n```\n\n### Using an abort signal\n\nAn abort signal can be passed to a process in order to abort it at a later\ntime. This will result in the process being killed and `aborted` being set\nto `true`.\n\n```ts\nconst aborter = new AbortController();\nconst proc = x('node', ['./foo.mjs'], {\n  signal: aborter.signal\n});\n\n// elsewhere...\naborter.abort();\n\nawait proc;\n\nproc.aborted; // true\nproc.killed; // true\n```\n\n### Using with command strings\n\nIf you need to continue supporting commands as strings (e.g. \"command arg0 arg1\"),\nyou can use [args-tokenizer](https://github.com/TrySound/args-tokenizer),\na lightweight library for parsing shell command strings into an array.\n\n```ts\nimport {x} from 'tinyexec';\nimport {tokenizeArgs} from 'args-tokenizer';\n\nconst commandString = 'echo \"Hello, World!\"';\nconst [command, ...args] = tokenizeArgs(commandString);\nconst result = await x(command, args);\n\nresult.stdout; // Hello, World!\n```\n\n### Synchronous\n\nYou can use `xSync` for synchronous (blocking) execution:\n\n```ts\nimport {xSync} from 'tinyexec';\n\nconst result = xSync('ls', ['-l']);\n\n// result.stdout - the stdout as a string\n// result.stderr - the stderr as a string\n// result.exitCode - the process exit code as a number\n```\n\nLike the async API, you can iterate over lines:\n\n```ts\nconst result = xSync('ls', ['-l']);\n\nfor (const line of result) {\n  // line will be from stdout then stderr\n}\n```\n\nSince the synchronous API blocks the event loop, there are some features that are supported in the async API that the sync API does not support:\n\n- `signal`\n- `persist`\n- `kill()` method\n- `stdin` piping\n- `pipe()` method\n\nOther options like `timeout`, `throwOnError`, and `nodeOptions` work the same way.\n\n## API\n\nCalling `x(command[, args])` returns an awaitable `Result` which has the\nfollowing API methods and properties available:\n\n### `pipe(command[, args[, options]])`\n\nPipes the current command to another. For example:\n\n```ts\nx('ls', ['-l'])\n  .pipe('grep', ['js']);\n```\n\nThe parameters are as follows:\n\n- `command` - the command to execute (_without any arguments_)\n- `args` - an array of arguments\n- `options` - options object\n\n### `process`\n\nThe underlying Node.js `ChildProcess`. tinyexec keeps the surface minimal and does not re‑expose every child_process method/event. Use `proc.process` for advanced access (streams, events, etc.).\n\n```ts\nconst proc = x('node', ['./foo.mjs']);\n\nproc.process?.stdout?.on('data', (chunk) =\u003e {\n  // ...\n});\nproc.process?.once('close', (code) =\u003e {\n  // ...\n});\n```\n\n### `kill([signal])`\n\nKills the current process with the specified signal. By default, this will\nuse the `SIGTERM` signal.\n\nFor example:\n\n```ts\nconst proc = x('ls');\n\nproc.kill();\n```\n\n### `pid`\n\nThe current process ID. For example:\n\n```ts\nconst proc = x('ls');\n\nproc.pid; // number\n```\n\n### `aborted`\n\nWhether the process has been aborted or not (via the `signal` originally\npassed in the options object).\n\nFor example:\n\n```ts\nconst proc = x('ls');\n\nproc.aborted; // bool\n```\n\n### `killed`\n\nWhether the process has been killed or not (e.g. via `kill()` or an abort\nsignal).\n\nFor example:\n\n```ts\nconst proc = x('ls');\n\nproc.killed; // bool\n```\n\n### `exitCode`\n\nThe exit code received when the process completed execution.\n\nFor example:\n\n```ts\nconst proc = x('ls');\n\nproc.exitCode; // number (e.g. 1)\n```\n\n## Comparison with other libraries\n\n`tinyexec` aims to provide a lightweight layer on top of Node's own\n`child_process` API.\n\nSome clear benefits compared to other libraries are that `tinyexec` will be much lighter, have a much\nsmaller footprint and will have a less abstract interface (less \"magic\"). It\nwill also have equal security and cross-platform support to popular\nalternatives.\n\nThere are various features other libraries include which we are unlikely\nto ever implement, as they would prevent us from providing a lightweight layer.\n\nFor example, if you'd like write scripts rather than individual commands, and\nprefer to use templating, we'd definitely recommend\n[zx](https://github.com/google/zx). zx is a much higher level library which\ndoes some of the same work `tinyexec` does but behind a template string\ninterface.\n\nSimilarly, libraries like `execa` will provide helpers for various things\nlike passing files as input to processes. We opt not to support features like\nthis since many of them are easy to do yourself (using Node's own APIs).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinylibs%2Ftinyexec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinylibs%2Ftinyexec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinylibs%2Ftinyexec/lists"}