Skip to main content
The Archil TypeScript SDK is the disk package on npm. It’s a pure-JavaScript control-plane client and CLI: create disks, list and inspect them, manage who can mount them, and run commands against them with disk.exec.
disk has no native dependencies and requires Node.js 22.19 or later. For the rare case where you need raw protocol access from Node (inodes, delegations, byte-level reads), there’s a separate @archildata/native package β€” most users will not need it.
Looking for the FUSE mount client? That’s the archil CLI, which mounts a disk as a real local filesystem. The TypeScript SDK does not mount disks; it talks to the control plane and runs serverless commands.

Configuration

The recommended pattern is a module-namespace import with a one-time configure call:
Both options fall back to environment variables (ARCHIL_API_KEY, ARCHIL_REGION) if omitted, so in most environments configure({}) β€” or skipping configure entirely β€” is enough. For multi-tenant scripts that need multiple credentials in one process, instantiate Archil directly instead:
For endpoints signed by a private certificate authority, pass tls.ca (a PEM string, Buffer, or array of either) to new Archil({ ..., tls: { ca } }). Like Node’s TLS ca option, it replaces the default trust list, so include getCACertificates() from node:tls if you still need the public CAs.
The API key is an account-level credential and is not the same thing as a disk token. API keys authenticate calls to the control plane (everything in this page); a disk token grants mount access to a single disk. See the disk users concept page.

Managing disks

Per-disk operations are methods on the Disk object itself, not top-level functions:

Executing commands

Disk.exec(command) runs a bash command inside a container with the file system already mounted, and returns stdout, stderr, exit code, and timing. See the Serverless Execution concept page for the full picture.
The disk is the working directory inside the container β€” commands can reference files using relative paths. For multi-disk execs (mount several disks at once, optionally pinned to a subdirectory or read-only), call archil.exec({ disks, command }) instead of Disk.exec. See Mounting multiple disks in one command.

ExecResult

Billing is based on executeMs β€” the wall-clock time your command runs β€” in 1ms increments, with a 100ms minimum per call. Queue time is not billed. The HTTP response returns after 5 minutes, and stdout and stderr are each capped at 128 KiB per invocation β€” pipe larger outputs to a file on the disk instead.

Fan-out

Because each exec runs in its own container, Promise.all is a map-reduce:
For the common case of searching files for a pattern, don’t hand-roll this β€” use Disk.grep, which fans the same work out for you and returns structured matches. See the bash tool for agents guide for an end-to-end example wiring disk.exec into an AI agent loop.

Searching files

Disk.grep(opts) searches the files on a disk for lines matching a regular expression, fanning the listing and matching out across many ephemeral containers so the search scales across many machines instead of one. It’s the productized version of the fan-out above β€” reach for it instead of Promise.all over exec("grep …") whenever you just want matching lines. See Search Files for the full model.
You control cost and latency with three knobs:
  • maxDurationSeconds β€” wall-clock deadline (default 30, capped at 30).
  • concurrency β€” max parallel workers (default 50). More workers scan a large dataset faster, at proportionally more compute.
  • maxResults β€” short-circuit once this many matches are collected (default 1000).
Always check stoppedReason β€” it tells you whether the search was exhaustive. When it stops early, the returned matches are a sample of whichever workers reported first, not the lexicographically first N:

GrepResult

Grep runs on the same container runtime as exec, so it bills the same way β€” on computeSecondsUsed, the summed execution time across the containers it dispatched.

Persistent sandboxes

Archil.sandboxes manages persistent Linux VMs. Each sandbox has a dedicated disk, accepts multiple commands over its lifetime, and can preserve CPU and memory state across pause and resume. See Persistent sandboxes for the lifecycle, interactive shells, services, forks, and limits.
maxTtlSeconds sets the hard timeout from 60 seconds to 24 hours (the default). idleTtlSeconds sets an optional idle timeout from 0 to 24 hours; 0 disables it. Both pause the VM, preserving memory and processes for resume(). Use sandbox.setTimeout() to update either setting; a session cannot exceed 24 hours even after a timeout reset. See Setting a time to live for examples and reset behavior. create, pause, resume, stop, start, and fork wait for completion by default. The server handles the initial wait; if its request budget expires first, the SDK continues polling. Pass { wait: false } to return as soon as the operation is accepted. A waited pause() throws SandboxPauseError if the sandbox does not reach paused. fork() pauses a running sandbox while the snapshot is taken and resumes it once the fork is accepted.
Use client.sandboxes.list() and .get(id) to retrieve sandboxes. A Sandbox provides refresh, fork, delete, pause, resume, stop, start, and setTimeout; exposePort, listPorts, unexposePort, and port-token methods for network services; getNetwork and updateNetwork for the firewall; plus run and attach for starting and reattaching to sandbox processes. exec runs a command and waits for its result. Pass an absolute cwd to run or exec to choose a working directory. The older processes.start and processes.connect methods are deprecated compatibility aliases. For an interactive command, provide terminal dimensions. The returned SandboxProcess accepts input and terminal resizes while streaming output to onOutput:

Mounting existing disks

Pass mounts when creating a sandbox to attach existing disks in addition to its internal root disk:
Each mount accepts disk (a disk ID or Disk object), path, subdirectory, readOnly, conditional, and queueMs. With a single mount, path is optional and defaults to /mnt/archil. Omitting mounts on start() keeps saved mounts; [] clears them and a list replaces them. See Persistent sandboxes for sharing and forking behavior.

Private images

images.build() waits until the image is ready, retrying interrupted builds up to three times. The default timeout is 30 minutes; set it with images.build(request, { timeoutSeconds: 600 }). Failed builds raise ImageBuildError; timeouts raise ArchilError with code IMAGE_BUILD_TIMEOUT. Use images.get(imageId) to read the current build state. Pass imageId instead of baseImage when creating a sandbox from a built image. See Sandbox images for reusing builds and updating tags.

Reading and writing objects

A Disk doubles as an S3-compatible bucket: read, write, delete, and list its files by key without mounting it. These methods talk to Archil’s S3 endpoint using your same API key β€” no separate S3 credentials or SigV4 signing on your part.
putObject handles any size with one call: small bodies go through a single request, and larger bodies are uploaded as a multipart upload automatically β€” split into parts, uploaded with bounded concurrency, and assembled, aborting the upload if any part fails so nothing is left half-staged. You don’t pick a different method for big files. Tune the switch point and parallelism with options:
For very large objects the part size grows automatically so the upload never exceeds S3’s 10,000-part limit. listObjects auto-paginates by default, returning every matching key. The first argument is a key prefix; a non-recursive listing (the default) returns the immediate level as objects plus subdirectory commonPrefixes:
deleteObjects removes many keys in one round trip (auto-batched at S3’s 1,000-key limit). Unlike deleteObject, per-key failures are returned rather than thrown:
appendObject appends bytes to an existing object (creating it if absent) β€” handy for log-style writes. Each call may append at most 1 MiB; append in chunks to grow past that:
For manual control over the multipart lifecycle (e.g. uploading parts from separate processes), the raw S3 primitives live in the opt-in d.multipart namespace β€” create, uploadPart, complete, abort, listParts, listUploads. Most code never needs these; prefer putObject, which runs the lifecycle for you.
Transient failures (HTTP 429 and 5xx, plus network errors) are retried automatically with jittered exponential backoff before surfacing; other 4xx are caller errors and aren’t retried. The two non-idempotent operations β€” completeMultipartUpload and appendObject β€” are not auto-retried, since a retry after a succeeded-but-unacknowledged call would return a spurious NoSuchUpload or duplicate the appended bytes. Object-API failures throw ArchilS3Error (a subclass of ArchilError) with status (HTTP status), code (the S3 error code, e.g. "NoSuchKey"), requestId, and the raw XML body on raw. getObject on a missing key throws a 404 β€” use headObject / objectExists to probe without catching.

Share URLs

share generates a signed, time-limited URL that lets anyone download a file from the disk without credentials:
The returned URL supports HTTP Range requests and streams with a sensible Content-Type. After expiry, requests to the URL return 401.

Managing API keys

API keys are account-level, so these helpers live at the top level rather than on a Disk:

CLI

disk ships a CLI under the same name. See the disk CLI reference for the full command list.

Low-level protocol access

For the small number of integrations that need to speak Archil’s filesystem protocol directly from Node β€” inodes, delegations, byte-level reads, paginated directory enumeration β€” install @archildata/native alongside disk:
Then call Disk.mount(), which lazy-loads the native client:
@archildata/native ships prebuilt binaries for Linux (x64, arm64, glibc) and macOS (arm64). On other platforms, mount() throws; the rest of disk still works.
If you’re tempted to reach for @archildata/native to β€œrun a bash command on a disk,” use disk.exec instead β€” it gives you a real shell with the filesystem mounted in a container, with no native dependencies on the caller side.

Need a bash executor inside Node?

The legacy @archildata/just-bash package implements a JavaScript bash interpreter that talks to a disk through @archildata/native. It’s still published, but for almost every use case disk.exec is the better answer β€” it runs your command in a real container with the filesystem mounted, returns stdout/stderr/exit code, and has no native dependencies on the caller.