The library underneath
docker-api-mx
Every page of Docker Client MX talks to Docker through one library: a typed, class-based client for the Docker Engine API, written for this app and published on npm on its own. Use it wherever you talk to Docker from Node.js.
0.2.0 · MIT · Node.js 20+ · ESM and CommonJS
The app started on dockerode, and it served well. But the parts that mattered most here were the parts it left to you: typing the responses, splitting logs into stdout and stderr, cancelling a stream, and above all reaching a daemon over ssh — the app carried its own ssh tunnel just to make that work.
docker-api-mx does those things itself. Since release 1.53.1 the app runs on it, the tunnel is gone, and nothing on your screen had to change.
Typed, and in classes
Docker, Container, Image, Network, Volume, Exec, and for swarm Service, Node, Task, Secret and Config. Option and response types are exported, and responses keep an index signature, so a field the library does not list is still reachable.
Promises and async iterators
No callbacks. Pull, push and build progress are async iterables with lines() and wait(); events and stats are async generators you leave with break.
Logs that are already split
Without a TTY, Docker mixes stdout and stderr in one stream of frames. MultiplexedStream.demux() and frames() take them apart again, and leave a TTY stream alone.
Its own transport, ssh included
Unix sockets, Windows named pipes, TCP and TLS, and DOCKER_HOST as the CLI reads it. Over ssh it logs in, runs docker system dial-stdio and checks the host key against known_hosts — nothing to open on the server.
Every call can be cancelled
Each method takes an abortSignal. Pair it with AbortSignal.timeout() for a deadline per call, or stop a long pull or a followed log from elsewhere in your program.
Errors you can branch on
A refused request is a DockerError with statusCode, isNotFound and isConflict. A pull or build that fails halfway is a DockerStreamError with the daemon’s own message.
Quick start
One client, local or on a server.
Handles are cheap and make no request until you call a method on them. Option names follow the Engine API as they are, so the Docker documentation is the documentation.
- Containers: create, run, start, stop, exec, attach, logs, stats, archives, commit, export
- Images: pull, push, build (also BuildKit, with registry credentials), save, load, import, search
- Networks and volumes, including cluster volumes
- Disk usage, events and prune for every kind of object
- Swarm: services, nodes, tasks, secrets and configs
- Plugins and checkpoints
import { Docker, MultiplexedStream } from 'docker-api-mx';
const docker = new Docker();
// Pull an image and print the progress.
for await (const line of docker.pull('alpine:3').lines()) {
console.log(line);
}
// Start a container and read its logs, stdout and stderr apart.
const web = await docker.createContainer({
Image: 'nginx:alpine',
name: 'web',
HostConfig: { PortBindings: { '80/tcp': [{ HostPort: '8080' }] } },
});
await web.start();
await MultiplexedStream.demux(await web.logs({ tail: 20 }), process.stdout, process.stderr);
// The same code against a server, over ssh.
const server = Docker.fromEnvironment({ DOCKER_HOST: 'ssh://deploy@server.example.com' });
console.log((await server.version()).Version);