Repository: testcontainers/testcontainers-go (Go)

Issue:
[Feature]: Add mongodb-atlas-local module
### Problem

testcontainers-go does not have a module for [mongodb/mongodb-atlas-local](https://hub.docker.com/r/mongodb/mongodb-atlas-local).

### Solution

Add a [mongodb/mongodb-atlas-local](https://hub.docker.com/r/mongodb/mongodb-atlas-local) module.

### Benefit

This would enable users to run integration tests against MongoDB Atlas-specific features (e.g. Atlas Vector Search) without requiring a remote cluster. 

### Alternatives

Users could use a generic container, see [LangChainGo](https://github.com/tmc/langchaingo/blob/0672790bb23a2c7e546a4a7aeffc9bef5bbd8c0b/vectorstores/mongovector/mongovector_test.go#L41).

### Would you like to help contributing this feature?

Yes


Discussion: Hi @prestonvasquez, is it possible to use the atlas-local image with the current MongoDB module, or do we need to do some changes to it?
Hey @mdelapenya , I think this should be a separate module as it introduces features that are not applicable to a local MongoDB server, specifically [Atlas Search](https://www.mongodb.com/products/platform/atlas-search) and [Atlas Vector Search](https://www.mongodb.com/products/platform/atlas-vector-search). This will require AL-specific options such as `WithMongotLogFile`, `WithRunnerLogFile`, and `WithDisableTelemetry`.

Additionally, there is no explicit `rs.initiate()` requirement when using Atlas Local: the image boots up a single-node replica set under the hood because that’s required for the search functionality to work.

Suggest we add an `atlaslocal` module to avoid complicating the existing `mongodb` module.

For example, using `WithReplicaSet` with the `mongodb/mongodb-atlas-local:latest` image results in failure:

```go
func TestMongoDBWithAtlasLocal(t *testing.T) {
	ctx := context.Background()

	const imageName = "mongodb/mongodb-atlas-local:latest"

	container, err := mongodb.Run(ctx, imageName,
		mongodb.WithUsername("admin"),
		mongodb.WithPassword("password"),
		mongodb.WithReplicaSet("meep"),
	)
	if err != nil {
		dumpLogs(t, ctx, container)
	}
	require.NoError(t, err, "failed to start MongoDB container")

	host, err := container.Host(ctx)
	require.NoError(t, err, "failed to get container host")

	port, err := container.MappedPort(ctx, "27017")
	require.NoError(t, err, "failed to get mapped port")

	uri := fmt.Sprintf("mongodb://%s:%s/?directConnection=true", host, port.Port())

	client, err := mongo.Connect(options.Client().ApplyURI(uri))
	require.NoError(t, err, "failed to connect to MongoDB")

	defer func() {
		client.Disconnect(ctx)
	}()

	require.Eventually(t, func() bool {
		err := client.Ping(ctx, nil)
		return err == nil
	}, 60*time.Second, 5*time.Second)
}

// dumpLogs will dump the logs of the MongoDB Atlas Local container to the
// integration test output.
func dumpLogs(t *testing.T, ctx context.Context, ctr testcontainers.Container) {
	t.Helper()

	r, err := ctr.Logs(ctx)
	require.NoError(t, err)

	bytes, err := io.ReadAll(r)
	t.Logf("MongoDB Atlas Local logs:\n%s", string(bytes))
}
```

Output:

```
❯ go test -run TestMongoDBWithAtlasLocal -v -failfast
=== RUN   TestMongoDBWithAtlasLocal
2025/08/01 16:51:42 github.com/testcontainers/testcontainers-go - Connected to docker:
  Server Version: 28.1.1
  API Version: 1.49
  Operating System: Docker Desktop
  Total Memory: 7837 MB
  Labels:
    com.docker.desktop.address=unix:///Users/preston.vasquez/Library/Containers/com.docker.docker/Data/docker-cli.sock
  Testcontainers for Go Version: v0.38.0
  Resolved Docker Host: unix:///var/run/docker.sock
  Resolved Docker Socket Path: /var/run/docker.sock
  Test SessionID: bf7a67dd3c90323430e89f86391fca7ee6aa8a6e3e610eeb689aac156fc7c841
  Test ProcessID: eac140fb-b4ae-41c8-b842-bc8b375e5345
2025/08/01 16:51:42 🐳 Creating container for image mongodb/mongodb-atlas-local:latest
2025/08/01 16:51:42 🐳 Creating container for image testcontainers/ryuk:0.12.0
2025/08/01 16:51:42 ✅ Container created: 9d4331a8be03
2025/08/01 16:51:42 🐳 Starting container: 9d4331a8be03
2025/08/01 16:51:42 ✅ Container started: 9d4331a8be03
2025/08/01 16:51:42 ⏳ Waiting for container id 9d4331a8be03 image: testcontainers/ryuk:0.12.0. Waiting for: &{Port:8080/tcp timeout:<nil> PollInterval:100ms skipInternalCheck:false skipExternalCheck:false}
2025/08/01 16:51:43 🔔 Container is ready: 9d4331a8be03
2025/08/01 16:51:43 ✅ Container created: 117f12ac276d
2025/08/01 16:51:43 🐳 Starting container: 117f12ac276d
2025/08/01 16:51:43 ✅ Container started: 117f12ac276d
2025/08/01 16:51:43 ⏳ Waiting for container id 117f12ac276d image: mongodb/mongodb-atlas-local:latest. Waiting for: &{timeout:<nil> deadline:0x140003efca0 Strategies:[0x140004277d0 0x1400044e180]}
2025/08/01 16:51:43 container logs (container exec create: Error response from daemon: container 117f12ac276d19cccd2ec41d3c6909369ac3d4a255d1e6a0fe5ed2aec2509943 is not running
wait until ready: container exited with code 2):
/tmp/entrypoint-tc.sh: line 13: find: command not found
/tmp/entrypoint-tc.sh: line 32: exec: --: invalid option
exec: usage: exec [-cl] [-a name] [command [argument ...]] [redirection ...]
    testcontainers_test.go:29: MongoDB Atlas Local logs:
        /tmp/entrypoint-tc.sh: line 13: find: command not found
        /tmp/entrypoint-tc.sh: line 32: exec: --: invalid option
        exec: usage: exec [-cl] [-a name] [command [argument ...]] [redirection ...]
    testcontainers_test.go:31:
                Error Trace:    /Users/preston.vasquez/Developer/dev/third-party/testcontainers-go/testcontainers_test.go:31
                Error:          Received unexpected error:
                                generic container: start container: started hook: container exec create: Error response from daemon: container 117f12ac276d19cccd2ec41d3c6909369ac3d4a255d1e6a0fe5ed2aec2509943 is not running
                                wait until ready: container exited with code 2
                Test:           TestMongoDBWithAtlasLocal
                Messages:       failed to start MongoDB container
--- FAIL: TestMongoDBWithAtlasLocal (0.88s)
FAIL
exit status 1
FAIL    github.com/prestonvasquez/dev/third-party/testcontainers-go     1.447s
```



Fix (patch):
diff --git a/docs/modules/mongodb-atlaslocal.md b/docs/modules/mongodb-atlaslocal.md
new file mode 100644
index 0000000000..3b52e3d6b4
--- /dev/null
+++ b/docs/modules/mongodb-atlaslocal.md
@@ -0,0 +1,188 @@
+# MongoDB Atlas Local
+
+Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+## Introduction
+
+The MongoDB Atlas Local module for Testcontainers lets you spin up a local MongoDB Atlas instance in Docker using
+[mongodb/mongodb-atlas-local](https://hub.docker.com/r/mongodb/mongodb-atlas-local) for integration tests and
+development. This module supports SCRAM authentication, init scripts, and custom log file mounting.
+
+This module differs from the standard modules/mongodb Testcontainers module, allowing users to spin up a full local
+Atlas-like environment complete with Atlas Search and Atlas Vector Search.
+
+## Adding this module to your project dependencies
+
+Please run the following command to add the MongoDB Atlas Local module to your Go dependencies:
+
+```
+go get github.com/testcontainers/testcontainers-go/modules/mongodb/atlaslocal
+```
+
+## Usage example
+
+<!--codeinclude-->
+[Creating a MongoDB Atlas Local container](../../modules/mongodb/atlaslocal/examples_test.go) inside_block:runMongoDBAtlasLocalContainer
+<!--/codeinclude-->
+
+## Module Reference
+
+### Run function
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+The `atlaslocal` module exposes one entrypoint function to create the MongoDB Atlas Local container, and this
+function receives three parameters:
+
+```golang
+func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error)
+```
+
+- `context.Context`, the Go context.
+- `string`, the Docker image to use.
+- `testcontainers.ContainerCustomizer`, a variadic argument for passing options.
+
+#### Image
+
+Use the second argument in the `Run` function to set a valid Docker image.
+In example: `Run(context.Background(), "mongodb/mongodb-atlas-local:latest")`.
+
+### Container Options
+
+When starting the MongoDB Atlas Local container, you can pass options in a variadic way to configure it.
+
+#### WithUsername
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option sets the initial username to be created when the container starts, populating the
+`MONGODB_INITDB_ROOT_USERNAME` environment variable. You cannot mix this option with `WithUsernameFile`, as it will
+result in an error.
+
+#### WithPassword
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option sets the initial password to be created when the container starts, populating the
+`MONGODB_INITDB_ROOT_PASSWORD` environment variable. You cannot mix this option with `WithPasswordFile`, as it will
+result in an error.
+
+#### WithUsernameFile
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option mounts a local file as the MongoDB root username secret at `/run/secrets/mongo-root-username`
+and sets the `MONGODB_INITDB_ROOT_USERNAME_FILE` environment variable. The path must be absolute and exist; no-op if
+empty.
+
+#### WithPasswordFile
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option mounts a local file as the MongoDB root password secret at `/run/secrets/mongo-root-password` and
+sets the `MONGODB_INITDB_ROOT_PASSWORD_FILE` environment variable. The path must be absolute and exist; no-op if empty.
+
+#### WithNoTelemetry
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option disables the telemetry feature of MongoDB Atlas Local, setting the `DO_NOT_TRACK` environment
+variable to `1`.
+
+#### WithInitDatabase
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option allows you to specify a database name to be initialized when the container starts, populating
+the `MONGODB_INITDB_DATABASE` environment variable.
+
+#### WithInitScripts
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+Mounts a directory into `/docker-entrypoint-initdb.d`, running `.sh`/`.js` scripts on startup. Calling this function
+multiple times mounts only the latest directory.
+
+#### WithMongotLogFile
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the mongot logs to `/tmp/mongot.log` inside the container. See
+`(*Container).ReadMongotLogs` to read the logs locally.
+
+#### WithMongotLogToStdout
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the mongot logs to `/dev/stdout` inside the container. See
+`(*Container).ReadMongotLogs` to read the logs locally.
+
+#### WithMongotLogToStderr
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the mongot logs to `/dev/stderr` inside the container. See
+`(*Container).ReadMongotLogs` to read the logs locally.
+
+#### WithRunnerLogFile
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the runner logs to `/tmp/runner.log` inside the container. See
+`(*Container).ReadRunnerLogs` to read the logs locally.
+
+#### WithRunnerLogToStdout
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the runner logs to `/dev/stdout` inside the container. See
+`(*Container).ReadRunnerLogs` to read the logs locally.
+
+#### WithRunnerLogToStderr
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+This functional option writes the runner logs to `/dev/stderr` inside the container. See
+`(*Container).ReadRunnerLogs` to read the logs locally.
+
+{% include "../features/common_functional_options_list.md" %}
+
+### Container Methods
+
+The MongoDB Atlas Local container exposes the following methods:
+
+
+#### ConnectionString
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+The `ConnectionString` method returns the connection string to connect to the MongoDB Atlas Local container.
+It returns a string with the format `mongodb://<host>:<port>[/<db>]/?directConnection=true[&authSource=admin]`.
+
+It can be used to configure a MongoDB client (`go.mongodb.org/mongo-driver/v2/mongo`), e.g.:
+
+<!--codeinclude-->
+[Using ConnectionString with the MongoDB client](../../modules/mongodb/atlaslocal/examples_test.go) inside_block:connectToMongo
+<!--/codeinclude-->
+
+#### ReadMongotLogs
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+The `ReadMongotLogs` returns a reader for the log solution specified when constructing the container.
+
+
+<!--codeinclude-->
+[Using ReadMongotLogs with the MongoDB client](../../modules/mongodb/atlaslocal/examples_test.go) inside_block:mongotLogsRead
+<!--/codeinclude-->
+
+#### ReadRunnerLogs
+
+- Not available until the next release <a href="https://github.com/testcontainers/testcontainers-go"><span class="tc-version">:material-tag: main</span></a>
+
+The `ReadRunnerLogs` returns a reader for the log solution specified when constructing the container.
+
+
+<!--codeinclude-->
+[Using ReadRunnerLogs with the MongoDB client](../../modules/mongodb/atlaslocal/examples_test.go) inside_block:runnerLogsRead
+<!--/codeinclude-->
diff --git a/mkdocs.yml b/mkdocs.yml
index 1d6f55baea..0603401fc6 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -100,6 +100,7 @@ nav:
         - modules/milvus.md
         - modules/minio.md
         - modules/mockserver.md
+        - modules/mongodb-atlaslocal.md
         - modules/mongodb.md
         - modules/mssql.md
         - modules/mysql.md
diff --git a/modules/mongodb/atlaslocal/atlaslocal.go b/modules/mongodb/atlaslocal/atlaslocal.go
new file mode 100644
index 0000000000..91b9d811a2
--- /dev/null
+++ b/modules/mongodb/atlaslocal/atlaslocal.go
@@ -0,0 +1,144 @@
+package atlaslocal
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"net/url"
+	"os"
+
+	"github.com/testcontainers/testcontainers-go"
+	"github.com/testcontainers/testcontainers-go/wait"
+)
+
+const defaultPort = "27017/tcp"
+
+// Container represents the MongoDBAtlasLocal container type used in the module.
+type Container struct {
+	testcontainers.Container
+	userOpts options
+}
+
+// Run creates an instance of the MongoDBAtlasLocal container type.
+func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*Container, error) {
+	userOpts := options{}
+	for _, opt := range opts {
+		if apply, ok := opt.(Option); ok {
+			if err := apply(&userOpts); err != nil {
+				return nil, fmt.Errorf("apply option: %w", err)
+			}
+		}
+	}
+
+	if err := userOpts.validate(); err != nil {
+		return nil, fmt.Errorf("validate options: %w", err)
+	}
+
+	moduleOpts := []testcontainers.ContainerCustomizer{ // Set the defaults
+		testcontainers.WithExposedPorts(defaultPort),
+		testcontainers.WithWaitStrategy(wait.ForAll(wait.ForListeningPort(defaultPort), wait.ForHealthCheck())),
+		testcontainers.WithEnv(userOpts.env()),
+		testcontainers.WithFiles(userOpts.files...),
+	}
+
+	moduleOpts = append(moduleOpts, opts...)
+
+	container, err := testcontainers.Run(ctx, img, moduleOpts...)
+	var c *Container
+	if container != nil {
+		c = &Container{Container: container, userOpts: userOpts}
+	}
+
+	if err != nil {
+		return c, fmt.Errorf("run container: %w", err)
+	}
+
+	return c, nil
+}
+
+// ConnectionString returns the connection string for the MongoDB Atlas Local
+// container. If you provide a username and a password, the connection string
+// will also include them.
+func (ctr *Container) ConnectionString(ctx context.Context) (string, error) {
+	endpoint, err := ctr.PortEndpoint(ctx, defaultPort, "")
+	if err != nil {
+		return "", fmt.Errorf("port endpoint: %w", err)
+	}
+
+	uri := &url.URL{
+		Scheme: "mongodb",
+		Host:   endpoint,
+		Path:   "/",
+	}
+
+	// If MONGODB_INITDB_DATABASE is set, use it as the default database in the
+	// connection string.
+	if db := ctr.userOpts.database; db != "" {
+		uri.Path, err = url.JoinPath("/", db)
+		if err != nil {
+			return "", fmt.Errorf("join path: %w", err)
+		}
+	}
+
+	user, err := ctr.userOpts.parseUsername()
+	if err != nil {
+		return "", fmt.Errorf("parse username: %w", err)
+	}
+
+	password, err := ctr.userOpts.parsePassword()
+	if err != nil {
+		return "", fmt.Errorf("parse password: %w", err)
+	}
+
+	if user != "" && password != "" {
+		uri.User = url.UserPassword(user, password)
+	}
+
+	q := uri.Query()
+	q.Set("directConnection", "true")
+	if user != "" && password != "" {
+		q.Set("authSource", "admin")
+	}
+
+	uri.RawQuery = q.Encode()
+
+	return uri.String(), nil
+}
+
+// ReadMongotLogs returns a reader for mongot logs in the container. Reads from
+// stdout/stderr or /tmp/mongot.log if configured.
+//
+// This method return the os.ErrNotExist sentinel error if it is called with
+// no log file configured.
+func (ctr *Container) ReadMongotLogs(ctx context.Context) (io.ReadCloser, error) {
+	path := ctr.userOpts.mongotLogPath
+	if path == "" {
+		return nil, os.ErrNotExist
+	}
+
+	switch path {
+	case "/dev/stdout", "/dev/stderr":
+		return ctr.Logs(ctx)
+	default:
+		return ctr.CopyFileFromContainer(ctx, path)
+	}
+}
+
+// ReadRunnerLogs() returns a reader for runner logs in the container. Reads
+// from stdout/stderr or /tmp/runner.log if configured.
+//
+// This method return the os.ErrNotExist sentinel error if it is called with
+// no log file configured.
+func (ctr *Container) ReadRunnerLogs(ctx context.Context) (io.ReadCloser, error) {
+	path := ctr.userOpts.runnerLogPath
+	if path == "" {
+		return nil, os.ErrNotExist
+	}
+
+	switch path {
+	case "/dev/stdout", "/dev/stderr":
+		return ctr.Logs(ctx)
+	default:
+		return ctr.CopyFileFromContainer(ctx, path)
+	}
+}
diff --git a/modules/mongodb/atlaslocal/options.go b/modules/mongodb/atlaslocal/options.go
new file mode 100644
index 0000000000..0dc5734b92
--- /dev/null
+++ b/modules/mongodb/atlaslocal/options.go
@@ -0,0 +1,399 @@
+package atlaslocal
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/testcontainers/testcontainers-go"
+)
+
+const (
+	passwordContainerPath      = "/run/secrets/mongo-root-password"
+	usernameContainerPath      = "/run/secrets/mongo-root-username"
+	envMongotLogFile           = "MONGOT_LOG_FILE"
+	envRunnerLogFile           = "RUNNER_LOG_FILE"
+	envMongoDBInitDatabase     = "MONGODB_INITDB_DATABASE"
+	envMongoDBInitUsername     = "MONGODB_INITDB_ROOT_USERNAME"
+	envMongoDBInitPassword     = "MONGODB_INITDB_ROOT_PASSWORD"
+	envMongoDBInitUsernameFile = "MONGODB_INITDB_ROOT_USERNAME_FILE"
+	envMongoDBInitPasswordFile = "MONGODB_INITDB_ROOT_PASSWORD_FILE"
+	envDoNotTrack              = "DO_NOT_TRACK"
+)
+
+// Compiler check to ensure that Option implements the testcontainers.ContainerCustomizer interface.
+var _ testcontainers.ContainerCustomizer = (Option)(nil)
+
+type options struct {
+	username          string
+	password          string
+	localUsernameFile string
+	localPasswordFile string
+	noTelemetry       bool
+	database          string
+	mongotLogPath     string
+	runnerLogPath     string
+
+	files []testcontainers.ContainerFile
+}
+
+func (opts options) env() map[string]string {
+	env := map[string]string{}
+
+	if opts.username != "" {
+		env[envMongoDBInitUsername] = opts.username
+	}
+
+	if opts.password != "" {
+		env[envMongoDBInitPassword] = opts.password
+	}
+
+	if opts.localUsernameFile != "" {
+		env[envMongoDBInitUsernameFile] = usernameContainerPath
+	}
+
+	if opts.localPasswordFile != "" {
+		env[envMongoDBInitPasswordFile] = passwordContainerPath
+	}
+
+	if opts.noTelemetry {
+		env[envDoNotTrack] = "1"
+	}
+
+	if opts.database != "" {
+		env[envMongoDBInitDatabase] = opts.database
+	}
+
+	if opts.mongotLogPath != "" {
+		env[envMongotLogFile] = opts.mongotLogPath
+	}
+
+	if opts.runnerLogPath != "" {
+		env[envRunnerLogFile] = opts.runnerLogPath
+	}
+
+	return env
+}
+
+func (opts options) validate() error {
+	username := opts.username
+	password := opts.password
+
+	// If username or password is specified, both must be provided.
+	if username != "" && password == "" || username == "" && password != "" {
+		return errors.New("if you specify username or password, you must provide both of them")
+	}
+
+	usernameFile := opts.localUsernameFile
+	passwordFile := opts.localPasswordFile
+
+	// If username file or password file is specified, both must be provided.
+	if usernameFile != "" && passwordFile == "" || usernameFile == "" && passwordFile != "" {
+		return errors.New("if you specify username file or password file, you must provide both of them")
+	}
+
+	// Setting credentials both inline and using files will result in a panic
+	// from the container, so we short circuit here.
+	if (username != "" || password != "") && (usernameFile != "" || passwordFile != "") {
+		return errors.New("you cannot specify both inline credentials and files for credentials")
+	}
+
+	return nil
+}
+
+// parseUsername will return either the username provided by WithUsername or
+// from the local file specified by WithUsernameFile. If both are provided, this
+// function will return an error. If neither is provided, an empty string is
+// returned.
+func (opts options) parseUsername() (string, error) {
+	if opts.username == "" && opts.localUsernameFile == "" {
+		return "", nil
+	}
+
+	if opts.username != "" && opts.localUsernameFile != "" {
+		return "", errors.New("cannot specify both inline credentials and files for credentials")
+	}
+
+	if opts.username != "" {
+		return opts.username, nil
+	}
+
+	r, err := os.ReadFile(opts.localUsernameFile)
+	return strings.TrimSpace(string(r)), err
+}
+
+// parsePassword will return either the password provided by WithPassword or
+// from the local file specified by WithPasswordFile. If both are provided, this
+// function will return an error. If neither is provided, an empty string is
+// returned.
+func (opts options) parsePassword() (string, error) {
+	if opts.password == "" && opts.localPasswordFile == "" {
+		return "", nil
+	}
+
+	if opts.password != "" && opts.localPasswordFile != "" {
+		return "", errors.New("cannot specify both inline credentials and files for credentials")
+	}
+
+	if opts.password != "" {
+		return opts.password, nil
+	}
+
+	r, err := os.ReadFile(opts.localPasswordFile)
+	return strings.TrimSpace(string(r)), err
+}
+
+// Option is an option for the Redpanda container.
+type Option func(*options) error
+
+// Customize is a NOOP. It's defined to satisfy the testcontainers.ContainerCustomizer interface.
+func (o Option) Customize(*testcontainers.GenericContainerRequest) error {
+	// NOOP to satisfy interface.
+	return nil
+}
+
+// WithUsername sets the MongoDB root username by setting the
+// MONGODB_INITDB_ROOT_USERNAME environment variable.
+func WithUsername(username string) Option {
+	return func(opts *options) error {
+		if username != "" {
+			opts.username = username
+		}
+
+		return nil
+	}
+}
+
+// WithPassword sets the MongoDB root password by setting the the
+// MONGODB_INITDB_ROOT_PASSWORD environment variable.
+func WithPassword(password string) Option {
+	return func(opts *options) error {
+		if password != "" {
+			opts.password = password
+		}
+
+		return nil
+	}
+}
+
+// WithUsernameFile mounts a local file as the MongoDB root username secret at
+// /run/secrets/mongo-root-username and sets MONGODB_INITDB_ROOT_USERNAME_FILE.
+// The path must be absolute and exist; no-op if empty.
+func WithUsernameFile(usernameFile string) Option {
+	return func(opts *options) error {
+		if usernameFile == "" {
+			return nil
+		}
+
+		// Must be an absolute path.
+		if !filepath.IsAbs(usernameFile) {
+			return fmt.Errorf("username file mount path must be absolute, got: %s", usernameFile)
+		}
+
+		// Must exist and be a file.
+		info, err := os.Stat(usernameFile)
+		if err != nil {
+			return fmt.Errorf("username file does not exist or is not accessible: %w", err)
+		}
+
+		if info.IsDir() {
+			return fmt.Errorf("username file must be a file, got a directory: %s", usernameFile)
+		}
+
+		opts.localUsernameFile = usernameFile
+
+		opts.files = append(opts.files, testcontainers.ContainerFile{
+			HostFilePath:      usernameFile,
+			ContainerFilePath: usernameContainerPath,
+			FileMode:          0o444,
+		})
+
+		return nil
+	}
+}
+
+// WithPasswordFile mounts a local file as the MongoDB root password secret at
+// /run/secrets/mongo-root-password and sets MONGODB_INITDB_ROOT_PASSWORD_FILE.
+// Path must be absolute and an existing file; no-op if empty.
+func WithPasswordFile(passwordFile string) Option {
+	return func(opts *options) error {
+		if passwordFile == "" {
+			return nil
+		}
+
+		// Must be an absolute path.
+		if !filepath.IsAbs(passwordFile) {
+			return fmt.Errorf("password file mount path must be absolute, got: %s", passwordFile)
+		}
+
+		// Must exist and be a file.
+		info, err := os.Stat(passwordFile)
+		if err != nil {
+			return fmt.Errorf("password file does not exist or is not accessible: %w", err)
+		}
+
+		if info.IsDir() {
+			return fmt.Errorf("password file must be a file, got a directory: %s", passwordFile)
+		}
+
+		opts.localPasswordFile = passwordFile
+
+		opts.files = append(opts.files, testcontainers.ContainerFile{
+			HostFilePath:      passwordFile,
+			ContainerFilePath: passwordContainerPath,
+			FileMode:          0o444,
+		})
+
+		return nil
+	}
+}
+
+// WithNoTelemetry opts out of telemetry for the MongoDB Atlas Local
+// container by setting the DO_NOT_TRACK environment variable to 1.
+func WithNoTelemetry() Option {
+	return func(opts *options) error {
+		opts.noTelemetry = true
+
+		return nil
+	}
+}
+
+// WithInitDatabase sets MONGODB_INITDB_DATABASE environment variable so the
+// init scripts and the default connection string target the specified database
+// instead of the default "test" database.
+func WithInitDatabase(database string) Option {
+	return func(opts *options) error {
+		opts.database = database
+
+		return nil
+	}
+}
+
+// WithInitScripts mounts a directory containing .sh/.js init scripts into
+// /docker-entrypoint-initdb.d so they run in alphabetical order on startup. If
+// called multiple times, this function removes any prior init-scripts bind and
+// uses only the latest on specified.
+func WithInitScripts(scriptsDir string) Option {
+	return func(opts *options) error {
+		if scriptsDir == "" {
+			return nil
+		}
+
+		abs, err := filepath.Abs(scriptsDir)
+		if err != nil {
+			return fmt.Errorf("get absolute path of init scripts dir: %w", err)
+		}
+
+		st, err := os.Stat(abs)
+		if err != nil {
+			return fmt.Errorf("stat init scripts dir: %w", err)
+		}
+
+		if !st.IsDir() {
+			return fmt.Errorf("init scripts path is not a directory: %s", abs)
+		}
+
+		const dstDir = "/docker-entrypoint-initdb.d/"
+
+		filtered := opts.files[:0]
+		for _, file := range opts.files {
+			if !strings.HasPrefix(file.ContainerFilePath, dstDir) {
+				filtered = append(filtered, file)
+			}
+		}
+
+		opts.files = filtered
+
+		entries, err := os.ReadDir(abs)
+		if err != nil {
+			return fmt.Errorf("read init scripts dir: %w", err)
+		}
+
+		for _, entry := range entries {
+			if entry.IsDir() {
+				continue
+			}
+
+			name := entry.Name()
+			if !strings.HasSuffix(name, ".sh") && !strings.HasSuffix(name, ".js") {
+				continue
+			}
+
+			f := testcontainers.ContainerFile{
+				HostFilePath:      filepath.Join(abs, name),
+				ContainerFilePath: filepath.Join(dstDir, name),
+				FileMode:          0o644,
+			}
+
+			if strings.HasSuffix(name, ".sh") {
+				f.FileMode = 0o755 // Make shell scripts executable.
+			}
+
+			opts.files = append(opts.files, f)
+		}
+
+		return nil
+	}
+}
+
+// WithMongotLogStdout writes to /dev/stdout inside the container. See
+// (*Container).ReadMongotLogs to read the logs locally.
+func WithMongotLogToStdout() Option {
+	return func(opts *options) error {
+		opts.mongotLogPath = "/dev/stdout"
+
+		return nil
+	}
+}
+
+// WithMongotLogToStderr writes to /dev/stderr inside the container. See
+// (*Container).ReadMongotLogs to read the logs locally.
+func WithMongotLogToStderr() Option {
+	return func(opts *options) error {
+		opts.mongotLogPath = "/dev/stderr"
+
+		return nil
+	}
+}
+
+// WithMongotLogFile writes the mongot logs to /tmp/mongot.log inside the
+// container. See (*Container).ReadMongotLogs to read the logs locally.
+func WithMongotLogFile() Option {
+	return func(opts *options) error {
+		opts.mongotLogPath = "/tmp/mongot.log"
+
+		return nil
+	}
+}
+
+// WithRunnerLogToStdout writes to /dev/stdout inside the container. See
+// (*Container).ReadRunnerLogs to read the logs locally.
+func WithRunnerLogToStdout() Option {
+	return func(opts *options) error {
+		opts.runnerLogPath = "/dev/stdout"
+
+		return nil
+	}
+}
+
+// WithRunnerLogToStderr writes to /dev/stderr inside the container. See
+// (*Container).ReadRunnerLogs to read the logs locally.
+func WithRunnerLogToStderr() Option {
+	return func(opts *options) error {
+		opts.runnerLogPath = "/dev/stderr"
+
+		return nil
+	}
+}
+
+// WithRunnerLogFile writes the runner logs to /tmp/runner.log inside the
+// container. See (*Container).ReadRunnerLogs to read the logs locally.
+func WithRunnerLogFile() Option {
+	return func(opts *options) error {
+		opts.runnerLogPath = "/tmp/runner.log"
+
+		return nil
+	}
+}
diff --git a/modules/mongodb/mongodb.go b/modules/mongodb/mongodb.go
index 76a3c57125..844c525e11 100644
--- a/modules/mongodb/mongodb.go
+++ b/modules/mongodb/mongodb.go
@@ -17,6 +17,7 @@ import (
 var entrypointContent []byte
 
 const (
+	defaultPort         = "27017/tcp"
 	entrypointPath      = "/tmp/entrypoint-tc.sh"
 	keyFilePath         = "/tmp/mongo_keyfile"
 	replicaSetOptEnvKey = "testcontainers.mongodb.replicaset_name"
@@ -40,10 +41,10 @@ func RunContainer(ctx context.Context, opts ...testcontainers.ContainerCustomize
 func Run(ctx context.Context, img string, opts ...testcontainers.ContainerCustomizer) (*MongoDBContainer, error) {
 	req := testcontainers.ContainerRequest{
 		Image:        img,
-		ExposedPorts: []string{"27017/tcp"},
+		ExposedPorts: []string{defaultPort},
 		WaitingFor: wait.ForAll(
 			wait.ForLog("Waiting for connections"),
-			wait.ForListeningPort("27017/tcp"),
+			wait.ForListeningPort(defaultPort),
 		),
 		Env: map[string]string{},
 	}
@@ -118,7 +119,7 @@ func WithReplicaSet(replSetName string) testcontainers.CustomizeRequestOption {
 // ConnectionString returns the connection string for the MongoDB container.
 // If you provide a username and a password, the connection string will also include them.
 func (c *MongoDBContainer) ConnectionString(ctx context.Context) (string, error) {
-	endpoint, err := c.PortEndpoint(ctx, "27017/tcp", "")
+	endpoint, err := c.PortEndpoint(ctx, defaultPort, "")
 	if err != nil {
 		return "", err
 	}