Core container lifecycle management with comprehensive configuration options for creating, starting, and controlling Docker containers.
Main class for creating and configuring Docker containers with a fluent builder API.
/**
* Creates a container from a Docker image
* @param image - Docker image name (e.g., 'redis:7-alpine', 'postgres:14')
*/
class GenericContainer {
constructor(image: string);
/**
* Create container from a Dockerfile
* @param context - Build context directory path
* @param dockerfileName - Dockerfile name (default: 'Dockerfile')
* @returns Builder for configuring the Docker build
*/
static fromDockerfile(
context: string,
dockerfileName?: string
): GenericContainerBuilder;
/**
* Start the container with configured settings
* @returns Promise resolving to started container instance
*/
start(): Promise<StartedTestContainer>;
// Command and entrypoint configuration
withCommand(command: string[]): this;
withEntrypoint(entrypoint: string[]): this;
withName(name: string): this;
withWorkingDir(workingDir: string): this;
withUser(user: string): this;
withHostname(hostname: string): this;
// Environment configuration
withEnvironment(environment: Environment): this;
withLabels(labels: Labels): this;
withPlatform(platform: string): this;
// Network configuration
withExposedPorts(...ports: PortWithOptionalBinding[]): this;
withNetwork(network: StartedNetwork): this;
withNetworkMode(networkMode: string): this;
withNetworkAliases(...networkAliases: string[]): this;
withExtraHosts(extraHosts: ExtraHost[]): this;
withIpcMode(ipcMode: string): this;
// File and volume operations
withBindMounts(bindMounts: BindMount[]): this;
withTmpFs(tmpFs: TmpFs): this;
withCopyFilesToContainer(filesToCopy: FileToCopy[]): this;
withCopyDirectoriesToContainer(directoriesToCopy: DirectoryToCopy[]): this;
withCopyContentToContainer(contentsToCopy: ContentToCopy[]): this;
withCopyArchivesToContainer(archivesToCopy: ArchiveToCopy[]): this;
// Resource and capability configuration
withResourcesQuota(resourcesQuota: ResourcesQuota): this;
withSharedMemorySize(bytes: number): this;
withUlimits(ulimits: Ulimits): this;
withAddedCapabilities(...capabilities: string[]): this;
withDroppedCapabilities(...capabilities: string[]): this;
withPrivilegedMode(): this;
// Health and readiness
withHealthCheck(healthCheck: HealthCheck): this;
withWaitStrategy(waitStrategy: WaitStrategy): this;
withStartupTimeout(startupTimeoutMs: number): this;
// Lifecycle options
withReuse(): this;
withAutoRemove(autoRemove: boolean): this;
withPullPolicy(pullPolicy: ImagePullPolicy): this;
withDefaultLogDriver(): this;
withLogConsumer(logConsumer: (stream: Readable) => unknown): this;
}Usage Examples:
import { GenericContainer, Wait } from 'testcontainers';
// Basic container with port mapping
const redis = await new GenericContainer('redis:7-alpine')
.withExposedPorts(6379)
.start();
// Container with environment variables and volume
const postgres = await new GenericContainer('postgres:14')
.withEnvironment({
POSTGRES_USER: 'test',
POSTGRES_PASSWORD: 'test',
POSTGRES_DB: 'testdb'
})
.withExposedPorts(5432)
.withBindMounts([{
source: '/local/data',
target: '/var/lib/postgresql/data',
mode: 'rw'
}])
.withWaitStrategy(Wait.forLogMessage('database system is ready to accept connections'))
.start();
// Container with resource limits
const app = await new GenericContainer('myapp:latest')
.withExposedPorts(8080)
.withResourcesQuota({
memory: 0.512, // 512MB in GB
cpu: 1
})
.withUser('appuser')
.withWorkingDir('/app')
.start();
// Container with file copying
const nginx = await new GenericContainer('nginx:alpine')
.withExposedPorts(80)
.withCopyFilesToContainer([{
source: './config/nginx.conf',
target: '/etc/nginx/nginx.conf'
}])
.withCopyContentToContainer([{
content: '<html><body>Hello</body></html>',
target: '/usr/share/nginx/html/index.html'
}])
.start();Builder for creating containers from Dockerfiles with build-time configuration.
/**
* Builder for containers created from Dockerfiles
*/
class GenericContainerBuilder {
/**
* Set Docker build arguments
* @param buildArgs - Key-value pairs of build arguments
*/
withBuildArgs(buildArgs: BuildArgs): this;
/**
* Set image pull policy for base images during build
* @param pullPolicy - Pull policy configuration
*/
withPullPolicy(pullPolicy: ImagePullPolicy): this;
/**
* Enable or disable build cache
* @param cache - Whether to use build cache (default: true)
*/
withCache(cache: boolean): this;
/**
* Enable BuildKit for the build
*/
withBuildkit(): this;
/**
* Set target platform for multi-platform builds
* @param platform - Platform string (e.g., 'linux/amd64', 'linux/arm64')
*/
withPlatform(platform: string): this;
/**
* Set build target stage for multi-stage Dockerfiles
* @param target - Target stage name
*/
withTarget(target: string): this;
/**
* Build the image and return a GenericContainer instance
* @param image - Optional custom image name (default: auto-generated)
* @param options - Build options including deleteOnExit flag
* @returns Promise resolving to GenericContainer instance
*/
build(image?: string, options?: BuildOptions): Promise<GenericContainer>;
}Usage Example:
import { GenericContainer } from 'testcontainers';
// Build from Dockerfile with build args
const container = await GenericContainer
.fromDockerfile('./my-app', 'Dockerfile')
.withBuildArgs({
NODE_VERSION: '18',
BUILD_ENV: 'test'
})
.withTarget('test')
.withBuildkit()
.build();
const started = await container
.withExposedPorts(3000)
.start();Represents a running container with control and inspection methods.
/**
* Interface for controlling and inspecting running containers
*/
interface StartedTestContainer {
/**
* Stop the container
* @param options - Stop options including timeout and removal settings
*/
stop(options?: Partial<StopOptions>): Promise<StoppedTestContainer>;
/**
* Restart the container
* @param options - Restart options including timeout
*/
restart(options?: Partial<RestartOptions>): Promise<void>;
/**
* Commit container changes to a new image
* @param options - Commit options including image name and changes
* @returns Promise resolving to new image ID
*/
commit(options: CommitOptions): Promise<string>;
/**
* Get the Docker host address
* @returns Host address (e.g., 'localhost' or Docker machine IP)
*/
getHost(): string;
/**
* Get container's internal hostname
* @returns Container hostname
*/
getHostname(): string;
/**
* Get the first mapped port
* @returns Host port number
*/
getFirstMappedPort(): number;
/**
* Get host port mapped to a container port
* @param port - Container port number
* @param protocol - Optional protocol ('tcp' or 'udp')
* @returns Host port number
*/
getMappedPort(port: number, protocol?: string): number;
getMappedPort(portWithProtocol: `${number}/${"tcp" | "udp"}`): number;
/**
* Get container name
* @returns Container name
*/
getName(): string;
/**
* Get container labels
* @returns Object containing all container labels
*/
getLabels(): Labels;
/**
* Get container ID
* @returns Full container ID
*/
getId(): string;
/**
* Get names of networks the container is connected to
* @returns Array of network names
*/
getNetworkNames(): string[];
/**
* Get network ID for a specific network name
* @param networkName - Name of the network
* @returns Network ID
*/
getNetworkId(networkName: string): string;
/**
* Get container's IP address on a specific network
* @param networkName - Name of the network
* @returns IP address
*/
getIpAddress(networkName: string): string;
/**
* Copy archive from container
* @param path - Path in container to copy from
* @returns Readable stream of tar archive
*/
copyArchiveFromContainer(path: string): Promise<NodeJS.ReadableStream>;
/**
* Copy tar archive to container
* @param tar - Readable stream of tar archive
* @param target - Target path in container (default: '/')
*/
copyArchiveToContainer(tar: Readable, target?: string): Promise<void>;
/**
* Copy directories to container
* @param directoriesToCopy - Array of directory copy specifications
*/
copyDirectoriesToContainer(directoriesToCopy: DirectoryToCopy[]): Promise<void>;
/**
* Copy files to container
* @param filesToCopy - Array of file copy specifications
*/
copyFilesToContainer(filesToCopy: FileToCopy[]): Promise<void>;
/**
* Copy content to container
* @param contentsToCopy - Array of content copy specifications
*/
copyContentToContainer(contentsToCopy: ContentToCopy[]): Promise<void>;
/**
* Execute command in running container
* @param command - Command string or array of command parts
* @param opts - Execution options (working directory, user, environment)
* @returns Promise resolving to execution result with output and exit code
*/
exec(command: string | string[], opts?: Partial<ExecOptions>): Promise<ExecResult>;
/**
* Get container logs
* @param opts - Log options including since timestamp and tail count
* @returns Promise resolving to readable stream of logs
*/
logs(opts?: { since?: number; tail?: number }): Promise<Readable>;
/**
* Async disposal support for automatic cleanup
*/
[Symbol.asyncDispose](): Promise<void>;
}Usage Examples:
import { GenericContainer } from 'testcontainers';
const container = await new GenericContainer('postgres:14')
.withExposedPorts(5432)
.start();
// Get connection details
const host = container.getHost();
const port = container.getMappedPort(5432);
console.log(`Connect to: postgresql://${host}:${port}/postgres`);
// Execute commands
const result = await container.exec(['psql', '-U', 'postgres', '-c', 'SELECT version()']);
console.log(result.output);
// Copy files
await container.copyFilesToContainer([{
source: './init.sql',
target: '/docker-entrypoint-initdb.d/init.sql'
}]);
// Get logs
const logs = await container.logs({ tail: 100 });
logs.on('data', (line) => console.log(line));
// Network info
const networks = container.getNetworkNames();
const ip = container.getIpAddress(networks[0]);
// Cleanup
await container.stop();Represents a stopped container with limited operations.
/**
* Interface for stopped containers
*/
interface StoppedTestContainer {
/**
* Get container ID
* @returns Container ID
*/
getId(): string;
/**
* Copy archive from stopped container
* @param path - Path in container to copy from
* @returns Readable stream of tar archive
*/
copyArchiveFromContainer(path: string): Promise<NodeJS.ReadableStream>;
}Base class for creating custom container implementations with lifecycle hooks.
/**
* Abstract base class for custom started container implementations
* Wraps a StartedTestContainer and delegates all operations to it
*/
abstract class AbstractStartedContainer implements StartedTestContainer {
/**
* Construct a custom started container wrapper
* @param startedTestContainer - The underlying started container
*/
constructor(startedTestContainer: StartedTestContainer);
/**
* Optional lifecycle hook called before container stops
*/
protected containerStopping?(): Promise<void>;
/**
* Optional lifecycle hook called after container stops
*/
protected containerStopped?(): Promise<void>;
// All methods from StartedTestContainer interface are available
}Usage Example:
import { AbstractStartedContainer, GenericContainer, StartedTestContainer } from 'testcontainers';
class RedisContainer extends GenericContainer {
constructor() {
super('redis:7-alpine');
this.withExposedPorts(6379);
}
async start(): Promise<StartedRedisContainer> {
return new StartedRedisContainer(await super.start());
}
}
class StartedRedisContainer extends AbstractStartedContainer {
getConnectionUrl(): string {
return `redis://${this.getHost()}:${this.getMappedPort(6379)}`;
}
protected async containerStopping(): Promise<void> {
// Custom cleanup logic before stopping
console.log('Flushing Redis data...');
await this.exec(['redis-cli', 'FLUSHALL']);
}
}
// Usage
const redis = await new RedisContainer().start();
console.log(redis.getConnectionUrl()); // Custom method
await redis.stop(); // Calls containerStopping() hookBase class for custom stopped container implementations.
/**
* Abstract base class for custom stopped container implementations
*/
abstract class AbstractStoppedContainer implements StoppedTestContainer {
/**
* Construct a custom stopped container wrapper
* @param stoppedTestContainer - The underlying stopped container
*/
constructor(stoppedTestContainer: StoppedTestContainer);
getId(): string;
copyArchiveFromContainer(path: string): Promise<NodeJS.ReadableStream>;
}type Environment = { [key: string]: string };
type Labels = { [key: string]: string };
type BuildArgs = { [key: string]: string };
type TmpFs = { [dir: string]: string };
type BindMode = 'rw' | 'ro' | 'z' | 'Z';
interface BindMount {
source: string;
target: string;
mode?: BindMode;
}
interface FileToCopy {
source: string;
target: string;
mode?: number;
}
interface DirectoryToCopy {
source: string;
target: string;
mode?: number;
}
type Content = string | Buffer | Readable;
interface ContentToCopy {
content: Content;
target: string;
mode?: number;
}
interface ArchiveToCopy {
tar: Readable;
target: string;
}
interface ExtraHost {
host: string;
ipAddress: string;
}
interface ResourcesQuota {
memory?: number; // Memory limit in Gigabytes
cpu?: number; // CPU quota in units of CPUs
}
interface Ulimits {
[name: string]: {
hard: number | undefined;
soft: number | undefined;
};
}
interface HealthCheck {
test: ['CMD-SHELL', string] | ['CMD', ...string[]];
interval?: number;
timeout?: number;
retries?: number;
startPeriod?: number;
}
interface ExecOptions {
workingDir?: string;
user?: string;
env?: { [key: string]: string };
}
interface ExecResult {
output: string;
stdout: string;
stderr: string;
exitCode: number;
}
interface StopOptions {
timeout: number;
remove: boolean;
removeVolumes: boolean;
}
interface RestartOptions {
timeout: number;
}
interface CommitOptions {
repo?: string;
comment?: string;
author?: string;
pause?: boolean;
changes?: string[];
deleteOnExit?: boolean;
}
interface BuildOptions {
deleteOnExit: boolean;
}
type PortWithOptionalBinding =
| number
| `${number}/${'tcp' | 'udp'}`
| PortWithBinding;
interface PortWithBinding {
container: number;
host: number;
protocol?: 'tcp' | 'udp';
}
interface ImagePullPolicy {
shouldPull(): boolean;
}
type HealthCheckStatus = 'none' | 'starting' | 'unhealthy' | 'healthy';
type HostPortBindings = Array<{ hostIp: string; hostPort: number }>;
type Ports = { [containerPortWithProtocol: string]: HostPortBindings };
interface NetworkSettings {
networkId: string;
ipAddress: string;
}
interface InspectResult {
name: string;
hostname: string;
ports: Ports;
healthCheckStatus: HealthCheckStatus;
networkSettings: { [networkName: string]: NetworkSettings };
state: {
status: string;
running: boolean;
startedAt: Date;
finishedAt: Date | undefined;
};
labels: { [key: string]: string };
}