mrkeyoor.com_
Wed 23 Sept 02:49 UTC
npmInfraupdated 22 Sept 2026

dockerode review

dockerode 5.0.1 is a Node wrapper around the Docker Engine API. Container, image, network, volume, exec, and Swarm resources become small JavaScript objects, while request options and returned data retain Docker's own shapes. Image pulls, builds, logs, attach, exec, and stats stay as Node streams. Its docker-modem transport provides helpers for progress messages and Docker's multiplexed stdout and stderr frames. Version 5 removed uuid, requires Node 14.17 or newer, and 5.0.1 updates protobuf and gRPC packages. Our browser build failed because this client depends on Node networking and filesystem APIs and expects access to a Docker daemon.

Verdict

dockerode 5.0.1 installed in 18 seconds and 19 MB with 0 audit findings on our box, but it supplied no types and its browser bundle failed. It fits trusted Node automation that truly needs Docker streams and Engine objects; testcontainers or a few CLI calls are easier for narrower jobs.

We installed it

Lab card: what happened when we installed dockerodeScreenshot of dockerode documentation
Install✓ · 18s68 packages on disk · 19 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
Typesno TypeScript types found
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does dockerode install cleanly?

Yes. In a fresh container with an empty cache, npm install dockerode finished in 18 seconds, leaving 68 packages and 19 MB on disk. npm audit reported no known vulnerabilities.

Can dockerode run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does dockerode work with both ESM and CommonJS?

Yes. Both import 'dockerode' and require('dockerode') worked in Node 22 in our run. The package is published as CommonJS.

Does dockerode include TypeScript types?

No type declarations were found in our install, so TypeScript users need their own declarations.

dockerode or testcontainers: which should you use?

testcontainers: Use it for integration-test services when readiness, mapped ports, and teardown should be handled by the library. dockerode 5.0.1 installed in 18 seconds and 19 MB with 0 audit findings on our box, but it supplied no types and its browser bundle failed.

When should you not use dockerode?

TypeScript declarations must come from the installed package. dockerode 5.0.1 ships none, so TypeScript users also need the separately versioned @types/dockerode package.

API stability4/5Version 5 retains the long-standing Docker, Container, Image, Exec, Network, Volume, and Swarm object model. Its major release raised the Node minimum to 14.17 and removed uuid without replacing the client interface; 5.0.1 only changes protobuf and gRPC dependencies. Callers still inherit change from the Docker daemon because option names and returned objects intentionally mirror the Engine API, so pinning the daemon API version may matter even when dockerode methods stay the same.
Docs3/5The README demonstrates Unix-socket and TLS connections, callbacks and promises, container operations, image contexts, private pulls, hijacked exec sessions, followProgress, and demuxStream. It also states that input and output shapes come directly from Docker and links each method to Engine API documentation. That division is honest, though it forces readers to consult 2 sources and many examples still use var declarations and nested callbacks.
Maintenance4/5The unarchived repository was pushed on August 10, 2026, and GitHub lists 25 open issues and pull requests. npm published 5.0.1 on June 24 with protobuf and gRPC dependency updates, following a 5.0 release that changed the Node floor and removed uuid. Recent work is mostly compatibility and dependency maintenance, which matches a mature transport wrapper, but the package still has to follow changes in Docker's broad Engine API.
Ecosystem4/5npm counted 6,972,180 dockerode downloads in the latest completed week, while GitHub reports 4,940 stars. docker-modem provides the underlying Docker transport, and testcontainers covers a higher-level testing use case in the same Node ecosystem. The main integration gap is typing: our inspected 5.0.1 package contains no declarations, leaving TypeScript projects dependent on @types/dockerode 4.0.1 and its release timing.

Use it if

  • A trusted Node process needs to manage containers through the Engine API instead of parsing output from the docker command.
  • Your job consumes pull, build, attach, log, exec, or stats streams and can handle Docker's progress records and output framing.
  • The automation also controls images, networks, volumes, secrets, configs, or Swarm objects.
  • You prefer Docker API option objects and response bodies with only a thin JavaScript wrapper around them.
Skip it if

Setup reality

We installed dockerode 5.0.1 in a fresh Node 22 Bookworm sandbox in 18 seconds. npm left 68 packages and 19 MB on disk, while dockerode itself lists 6 direct dependencies, 0 peer dependencies, and 244 KB unpacked. npm audit found 0 known vulnerabilities. The CommonJS package has no exports map; require and ESM import both succeeded. It contains no TypeScript declarations. esbuild failed to make a browser bundle, which confirms this is Node-only code.

With no options, the client uses /var/run/docker.sock. The OS account must be able to open it, and mounting that socket into another container gives the workload control over the Docker host. Remote TLS needs the daemon host and port plus CA, client certificate, and private key buffers. Docker API fields pass through unchanged, so HostConfig, PortBindings, filters, and response formats come from the Engine reference.

A pull or buildImage promise resolves when the response stream arrives, not when all layers finish. Feed the stream to docker.modem.followProgress and reject its final error. For Tty false, attach and exec output includes Docker's 8-byte framing headers; use demuxStream to split stdout and stderr. A build context assembled from context and src contains only the listed files, so an omitted COPY input fails during the image build.

Most methods accept either callbacks or promises. docker.run returns an EventEmitter with a callback and a promise without one, so mixing styles changes control flow. After exec output ends, call inspect to read ExitCode. Daemon errors do not become a special dockerode error hierarchy. Set request timeouts, handle a missing socket, pass registry credentials carefully, and remove only containers and volumes your service owns.

Patterns

Connect through the local Docker socket connect-to-local-engine

const Docker = require('dockerode')

const docker = new Docker({ socketPath: '/var/run/docker.sock' })
const version = await docker.version()
console.log(version.ApiVersion)

The process needs permission to open /var/run/docker.sock. That permission should be treated as control of the Docker host.

Use mutual TLS with a remote daemon connect-with-tls

const fs = require('node:fs')
const Docker = require('dockerode')

const docker = new Docker({
  protocol: 'https',
  host: 'docker.internal',
  port: 2376,
  ca: fs.readFileSync('certs/ca.pem'),
  cert: fs.readFileSync('certs/client.pem'),
  key: fs.readFileSync('certs/client-key.pem'),
})

Keep the private key outside the application image and verify the server certificate. An unauthenticated TCP daemon exposes host control to the network.

List running containers with one label list-running-containers

const rows = await docker.listContainers({
  all: true,
  filters: JSON.stringify({
    label: ['com.example.role=worker'],
    status: ['running'],
  }),
})

for (const row of rows) console.log(row.Id, row.Names)

The filters query value is JSON text. List results are summaries; call inspect on a Container object for its complete configuration.

Start a container on an assigned port create-start-inspect

const container = await docker.createContainer({
  Image: 'redis:7',
  HostConfig: {
    AutoRemove: true,
    PortBindings: { '6379/tcp': [{ HostPort: '0' }] },
  },
})
await container.start()
const detail = await container.inspect()
console.log(detail.NetworkSettings.Ports['6379/tcp'][0].HostPort)

HostPort 0 asks Docker to choose a host port. Inspect after start to discover it; AutoRemove deletes the container when it exits.

Run a short command and wait run-one-command

const [result, container] = await docker.run(
  'alpine:3.20',
  ['sh', '-c', 'printf ready'],
  process.stdout,
  { HostConfig: { AutoRemove: true } },
)
console.log(result.StatusCode, container.id)

Without a callback, run resolves after the command and returns the status plus Container object. AutoRemove may have deleted that container already.

Wait for an image pull to complete pull-and-wait

const stream = await docker.pull('postgres:16')
await new Promise((resolve, reject) => {
  docker.modem.followProgress(stream, (error, events) => {
    if (error) reject(error)
    else resolve(events)
  })
})

docker.pull returns the response stream before the image is usable. Start dependent work only after followProgress calls its completion handler.

Build from an explicit file list build-an-image

const stream = await docker.buildImage(
  { context: process.cwd(), src: ['Dockerfile', 'package.json', 'src'] },
  { t: 'example/app:local' },
)
await new Promise((resolve, reject) => {
  docker.modem.followProgress(stream, error => error ? reject(error) : resolve())
})

Only entries in src reach this generated build context. Any file referenced by COPY must appear in the list or inside a listed directory.

Split a container's stdout and stderr follow-container-logs

const output = await container.logs({
  follow: true,
  stdout: true,
  stderr: true,
  tail: 100,
})

docker.modem.demuxStream(output, process.stdout, process.stderr)

demuxStream is for containers created with Tty false. A TTY combines both channels and can be piped without Docker frame parsing.

Inspect an exec command's exit status exec-and-check-status

const command = await container.exec({
  Cmd: ['sh', '-c', 'test -f /app/ready'],
  AttachStdout: true,
  AttachStderr: true,
})
const stream = await command.start({ hijack: true, stdin: false })
docker.modem.demuxStream(stream, process.stdout, process.stderr)
await new Promise(resolve => stream.on('end', resolve))
const result = await command.inspect()
if (result.ExitCode !== 0) throw new Error(`exec exited ${result.ExitCode}`)

exec.start exposes output without returning the final status. Wait for the stream to end, then inspect the exec and read ExitCode.

Read a single resource sample read-one-stats-sample

const stats = await container.stats({ stream: false })
console.log({
  memory: stats.memory_stats.usage,
  cpuTotal: stats.cpu_stats.cpu_usage.total_usage,
})

stream false requests 1 daemon sample. The response contains CPU counters rather than a finished percentage, so monitoring code must calculate that rate.

Authenticate a private image pull pull-private-image

const stream = await docker.pull('registry.example.com/team/api:2026-08', {
  authconfig: {
    username: process.env.REGISTRY_USER,
    password: process.env.REGISTRY_TOKEN,
    serveraddress: 'registry.example.com',
  },
})
await new Promise((resolve, reject) => {
  docker.modem.followProgress(stream, error => error ? reject(error) : resolve())
})

docker-modem encodes authconfig for the daemon. Keep the registry token out of logs and read progress errors for authentication failures.

Stop and delete an owned container remove-a-container

const container = docker.getContainer(containerId)
const state = await container.inspect()
if (state.State.Running) await container.stop({ t: 10 })
await container.remove({ v: true })

Limit deletion to containers created by your service. The v option also removes anonymous volumes, which may contain data.

Alternatives

PackageRegistryPick it when
testcontainersnpmUse it for integration-test services when readiness, mapped ports, and teardown should be handled by the library.
docker-composenpmUse it when a checked-in Compose file already defines the stack and Node only needs to bring that stack up or down.
execanpmUse it when a few docker CLI calls are enough and CLI-compatible output matters more than direct Engine objects.

More infra guides

boto3 · opentelemetry-api · psutil · distro · @opentelemetry/api · google-cloud-storage · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.