Skip to content

Separate module-author internals from the user-facing entry point #1562

Open

Description

@cristianrgreco

What happens

testcontainers has a single entry point (main: build/index.js, no exports map) that serves both test authors and module authors. Utilities that exist for the modules and for core itself are exported next to the user-facing API, and every one of them is covered by semver:

  • log, IntervalRetry, Retry
  • Uuid, RandomUuid, randomUuid
  • PortGenerator, RandomPortGenerator
  • BoundPorts, getContainerPort, hasHostBinding
  • getReaper, LABEL_TESTCONTAINERS_SESSION_ID
  • ContainerRuntimeClient, getContainerRuntimeClient, waitForContainer

Dockerode types are part of the public contract as well:

  • WaitStrategy.waitUntilReady(container: Dockerode.Container, ...)
  • StartupCheckStrategy.checkStartupState(dockerClient: Dockerode, ...)
  • the protected createOpts: ContainerCreateOptions and hostConfig: HostConfig on GenericContainer, which subclasses read and write directly

That is why @types/dockerode is a runtime dependency, and why a Dockerode major is a breaking change here.

Because there is no exports map, consumers can also import anything under testcontainers/build/....

Usage inside this repo is narrow. Most modules import only GenericContainer, AbstractStartedContainer, Wait and StartedTestContainer. Five of them (kafka, redpanda, localstack, ollama, couchbase) reach for the runtime client, BoundPorts, waitForContainer or getReaper.

Expected

  • The main entry exports what a test author needs.
  • Module-author utilities move to a separate subpath (for example testcontainers/module) with its own, looser stability promise.
  • An exports map closes off deep imports.
  • Dockerode types stay out of the user-facing signatures where possible.

Where

  • packages/testcontainers/src/index.ts
  • packages/testcontainers/package.json
  • biome.json (the import boundary rule that pins modules to the testcontainers entry point)

Notes

Dependencies

Activity

  1. added
    maintenanceImprovements that do not change functionality
    majorAn incompatible API change
    on Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    maintenanceImprovements that do not change functionalitymajorAn incompatible API change

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions