Napbat.Testcontainers.Build
0.1.0
dotnet add package Napbat.Testcontainers.Build --version 0.1.0
NuGet\Install-Package Napbat.Testcontainers.Build -Version 0.1.0
<PackageReference Include="Napbat.Testcontainers.Build" Version="0.1.0" />
<PackageVersion Include="Napbat.Testcontainers.Build" Version="0.1.0" />
<PackageReference Include="Napbat.Testcontainers.Build" />
paket add Napbat.Testcontainers.Build --version 0.1.0
#r "nuget: Napbat.Testcontainers.Build, 0.1.0"
#:package Napbat.Testcontainers.Build@0.1.0
#addin nuget:?package=Napbat.Testcontainers.Build&version=0.1.0
#tool nuget:?package=Napbat.Testcontainers.Build&version=0.1.0
Testcontainers.Build
Build Docker images from folders, HTTP(S) build contexts, or Git repositories. Use the images with Testcontainers in C# or Rust, without first publishing your application image to GHCR or another registry.
Both libraries provide fluent requests, replaceable providers and build backends, and explicit resource ownership. Docker can still download base images and the Testcontainers resource reaper.
| Component | Name |
|---|---|
| NuGet package | Napbat.Testcontainers.Build |
| C# namespace | Testcontainers.Build |
| Rust crate | testcontainers-build (import as testcontainers_build) |
| Image builder in both libraries | ImageBuilder |
Run the examples
Run these commands from the repository root:
dotnet run --project dotnet/examples/Testcontainers.Build.Examples -- local
dotnet run --project dotnet/examples/Testcontainers.Build.Examples -- remote
dotnet run --project dotnet/examples/Testcontainers.Build.Examples -- git
cargo run -p testcontainers-build --example local
cargo run -p testcontainers-build --example remote
cargo run -p testcontainers-build --example git-source
Each example builds an image, starts a container, waits for readiness, checks its files, and removes the container and image.
| Example | Source and features |
|---|---|
| Local | Sample folder; nested Dockerfile, build argument, target stage, disabled layer cache, timeout, and .dockerignore. |
| Remote | Filtered tar archive served by a temporary HTTP container; Docker downloads the context over HTTP. |
| Git | Temporary repository; pinned commit and checkout subdirectory. The checkout is removed after the build. |
Browse the C# examples or Rust examples. Both use the shared example context.
Prerequisites
- Docker CLI with buildx and a running Linux container engine.
- Git on
PATHfor Git sources and the Git examples. - .NET SDK 10 and the .NET 8 runtime for the C# solution and examples.
- A current stable Rust toolchain. The last full verification used Rust 1.98.
The Docker CLI and Testcontainers must use the same daemon. Configure DOCKER_HOST
when needed; do not assume a Docker CLI context change also changes Testcontainers.
The remote example uses host.docker.internal on Docker Desktop and 127.0.0.1
on Linux. Set TESTCONTAINERS_BUILD_HTTP_HOST if your builder needs another address.
Use the libraries
For C#, reference Testcontainers.Build.csproj
or a locally built NuGet package. For Rust, add a path dependency on
rust/testcontainers-build. Add testcontainers = "0.28"
and Tokio when using its native container API. See package commands.
C# fluent API
This snippet uses the sample context when run from the repository root:
using DotNet.Testcontainers.Builders;
using Testcontainers.Build;
await using var image = await new ImageBuilder()
.WithSource(new FolderSource("rust/testcontainers-build/examples/context"))
.WithDockerfile("container/Dockerfile")
.WithBuildArgument("GREETING", "hello from C#")
.WithTarget("runtime")
.WithTimeout(TimeSpan.FromMinutes(2))
.BuildAsync();
await using var container = image.ToContainerBuilder()
.WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("example-ready"))
.Build();
await container.StartAsync();
// Use the container here. Its disposal runs before image disposal.
Configuration methods return new requests. Reuse a common request to create
independent variants. WithOptions copies caller-owned build arguments. Pass a
cancellation token to BuildAsync to cancel resolution or the build. The direct
BuildAsync(source, options, cancellationToken) API is also available.
Rust fluent API
In an async function, build the same context with:
use testcontainers_build::{FolderSource, ImageBuilder};
let mut image = ImageBuilder::default()
.with_source(FolderSource::new("rust/testcontainers-build/examples/context"))
.with_dockerfile("container/Dockerfile")
.with_build_argument("GREETING", "hello from Rust")
.with_target("runtime")
.build()
.await?;
// Configure native container wait conditions with image.image().
// Remove all containers before removing the image.
image.remove().await?;
Rust with_* methods consume and return the request. The direct
build(&source, &options) API accepts borrowed inputs. See the
Rust package README for a complete program
and the example helper for
container checks and cleanup on error paths.
Sources and build options
| Source | C# | Rust |
|---|---|---|
| Folder | new FolderSource(path) |
FolderSource::new(path) |
| HTTP(S) | new RemoteUriSource(uri) |
RemoteUriSource::new(uri)? |
| Git | new GitSource(new GitRequest(repository, revision, subdirectory)) |
GitSource::new(GitRequest::new(repository).with_revision(revision).with_subdirectory(subdirectory)) |
Supply the source to WithSource or with_source. Use a full Git commit ID for
repeatable builds. Branches and tags can change.
| Option | C# method | Rust method | Default |
|---|---|---|---|
| Dockerfile | WithDockerfile |
with_dockerfile |
Dockerfile, relative to the context |
| Build argument | WithBuildArgument |
with_build_argument |
None; a repeated name replaces its value |
| Target stage | WithTarget |
with_target |
Last Dockerfile stage |
| Platform | WithPlatform |
with_platform |
Docker default |
| Disable layer cache | WithNoCache |
with_no_cache |
Cache enabled |
| Timeout | WithTimeout |
with_timeout |
Ten minutes, including source resolution |
| Replace all options | WithOptions |
with_options |
A new BuildOptions value |
Validation runs before source resolution. Use forward slashes for context-relative paths. Absolute paths, parent traversal, and symbolic links in the selected Git subdirectory or Dockerfile path are rejected. Docker handles other links in the context. Timeouts must be positive and at most 4,294,967,294 milliseconds.
Source behavior and cleanup
Folder sources use the caller's directory without copying or deleting it. Git sources fetch one revision into a temporary checkout and delete it after the build. The default Git provider uses Git's authentication configuration and disables terminal prompts. It does not explicitly initialize submodules or manage Git LFS. Use a custom provider when the checkout needs those steps.
HTTP(S) sources pass a URI to Docker. The builder must be able to reach it. The
response can be a standard tar archive, optionally compressed with gzip, or a
plain Dockerfile. ZIP is not supported. A plain remote Dockerfile has no local
files for COPY.
Docker applies ignore rules to folder and Git contexts. Filter remote archives
before creation: Docker uses the files already in the archive and does not apply
its .dockerignore. The remote examples include only the required sample files.
Each build creates a unique local tag and can reuse Docker's layer cache. Image removal removes the owned tag; it does not prune shared caches or remove containers. Remove containers before their image.
- C#:
await usingremoves the image at scope exit. Declare the image before the container so disposal happens in the correct order. - Rust: call
remove().awaiton success and error paths.Dropdoes not perform asynchronous image removal.
The C# adapter disables registry pulls. Rust Testcontainers 0.28 uses the local image first but can attempt a pull if it is missing. Keep the image available until all containers are removed.
Build errors include tool output. Do not put secrets in build arguments or URLs; tools can include them in diagnostics. C# cancellation stops the subprocess tree. Rust requests subprocess termination when its future is dropped, without a guarantee that all descendants stop.
External sources in the examples
dotnet run --project dotnet/examples/Testcontainers.Build.Examples -- remote https://example.com/context.tar.gz
dotnet run --project dotnet/examples/Testcontainers.Build.Examples -- git https://example.com/service.git COMMIT services/app
cargo run -p testcontainers-build --example remote -- https://example.com/context.tar.gz
cargo run -p testcontainers-build --example git-source -- https://example.com/service.git COMMIT services/app
These URLs and COMMIT are placeholders. Inputs must follow the
sample contract:
container/Dockerfile, a runtime stage, payload.txt, /message in the image,
and an example-ready startup message. Checks expect the sample payload at
/app/payload.txt and no /app/excluded.txt. Adapt the source and checks for your
application. These are example requirements, not library restrictions.
Extension points
| Responsibility | C# | Rust |
|---|---|---|
| Resolve a build context | IBuildContextProvider |
BuildContextProvider |
| Check out Git | IGitProvider |
GitProvider |
| Build and remove an image | IImageBuildBackend |
ImageBuildBackend |
Inject a Git provider into GitSource, or an image backend into ImageBuilder.
This permits hosting APIs, checkout caches, and Docker Engine clients without
changing orchestration. The default backend is DockerCliBackend.
Providers return BuildContext. In C#, supply a cleanup callback for owned
resources. In Rust, use BuildContext::with_owner to retain a resource guard. The
context stays alive until the backend finishes. Providers must honor C# cancellation
tokens or Rust future cancellation.
Project layout and maintenance
Testcontainers.Build.slnx
Cargo.toml # workspace and lint policy
dotnet/
Directory.Build.props
src/Testcontainers.Build/
tests/Testcontainers.Build.Tests/
examples/Testcontainers.Build.Examples/
rust/testcontainers-build/
Cargo.toml # inherits workspace lints
src/lib.rs
src/ # focused modules
tests/builders.rs
tests/providers/main.rs
tests/docker/main.rs
tests/common/mod.rs
examples/local/main.rs
examples/remote/main.rs
examples/git-source/main.rs
examples/common/
examples/context/ # shared with C# examples
spec/path-cases.json # shared path contract
fixtures/app/ # shared Docker test fixture
The Rust package follows the Cargo layout guide.
The virtual workspace keeps generated files in target at the repository root.
This library repository does not track Cargo.lock; Cargo generates it locally.
Every member inherits Cargo.toml lint levels with [lints] workspace = true.
See AGENTS.md for coding and documentation rules.
The implementations remain native. They share fixtures rather than generated async or resource-management code. A future declarative build manifest could provide a code generation boundary; no generator is required now.
Verify changes
These checks do not require Docker; Docker tests are skipped by default:
dotnet test Testcontainers.Build.slnx
dotnet format Testcontainers.Build.slnx --verify-no-changes --no-restore
cargo test --workspace
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo doc --workspace --no-deps
Enable Docker tests in PowerShell:
$env:TESTCONTAINERS_BUILD_DOCKER_TESTS = "1"
dotnet test Testcontainers.Build.slnx
cargo test --workspace --test docker -- --ignored
In a POSIX shell, use TESTCONTAINERS_BUILD_DOCKER_TESTS=1 dotnet test Testcontainers.Build.slnx.
Run the examples after changes to their behavior.
CI runs tests, examples, lints, documentation, and package builds.
Build local packages
dotnet pack dotnet/src/Testcontainers.Build/Testcontainers.Build.csproj -c Release -o artifacts
cargo package -p testcontainers-build
The NuGet package goes to artifacts/. The Rust archive goes to target/package/
and includes the examples and their context. These commands do not publish packages.
Dependency compatibility
The NuGet package requires Testcontainers 4.14.0 or newer. This is a minimum version, not an exact pin. A compatible direct reference in the consuming project can satisfy the dependency without a second package version for that target.
The Rust crate uses testcontainers = "0.28", which permits versions from 0.28.0
up to, but excluding, 0.29.0. Use the same compatible range in an application that
uses the native Testcontainers API. A different minor release can create duplicate
crates with distinct types. Do not widen the range across breaking versions
without verifying the adapter. See Cargo version requirements
and NuGet resolution.
Publish packages
The publishing guide covers registry access, release versions, dry runs, and tag-based publishing. CI stores NuGet packages, symbols, and the Rust crate as downloadable artifacts. A dry run does not upload packages to a registry.
License
Both libraries use the MIT license.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Testcontainers (>= 4.14.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 173 | 9/5/2026 |