Embedding TinyS3 in your application
TinyS3's core is an ordinary Java library — you can run a full S3 endpoint inside any JVM process. The most common use is integration tests that need a real S3 API without containers, but it works just as well as a storage component inside a larger application.
Requires Java 25.
Dependency
Published to Maven Central:
kotlin
// Gradle
testImplementation("dev.totis:tiny-s3-lib:<version>")
// or implementation(...) when embedding for realxml
<!-- Maven -->
<dependency>
<groupId>dev.totis</groupId>
<artifactId>tiny-s3-lib</artifactId>
<version><!-- version --></version>
</dependency>Minimal server
java
import dev.totis.tinys3.S3Server;
import dev.totis.tinys3.auth.Credentials;
S3Server server = new S3Server.Builder()
.withPort(8000)
.withCredentials(new Credentials("access-key", "secret-key", "us-east-1"))
.withStorageDir("storage")
.build();
server.start();
// ... server.stop() when doneIn-memory server for tests
Nothing touches disk; perfect for JUnit:
java
class MyS3IntegrationTest {
private S3Server server;
@BeforeEach
void setUp() {
server = new S3Server.Builder()
.withPort(9876)
.withCredentials(new Credentials("test", "test", "us-east-1"))
.withInMemory()
.build();
server.start();
}
@AfterEach
void tearDown() {
server.stop();
}
@Test
void uploadsAndDownloads() {
S3Client s3 = S3Client.builder()
.endpointOverride(URI.create("http://localhost:9876"))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create("test", "test")))
.region(Region.US_EAST_1)
.forcePathStyle(true)
.build();
s3.createBucket(b -> b.bucket("test-bucket"));
// ...
}
}Erasure-coded storage
Bring the file-system module for fault-tolerant storage:
java
StorageConfig config = StorageConfig.create(
List.of("/disk1", "/disk2", "/disk3", "/disk4", "/disk5", "/disk6"),
new ErasureConfig(4, 2, 4096)); // 4 data + 2 parity shards
FileSystem fs = new ErasureCodedFileSystem(config);
S3Server server = new S3Server.Builder()
.withPort(8000)
.withCredentials(credentials)
.withFileSystem(fs)
.build();Builder reference
| Method | Purpose |
|---|---|
withPort(int) | Listen port |
withCredentials(Credentials) | Root credential (repeatable for multi-user) |
withStorageDir(String) / withInMemory() / withFileSystem(FileSystem) | Storage backend |
withBaseUrl(String) | Advertised endpoint for presigned URLs |
withTls(TlsConfig) | Native TLS |
withSseMasterKey(String) | Base64 master key enabling SSE-S3 / SSE-KMS |
withLifecycleInterval(Duration) / withLifecycleDisabled() | Lifecycle expiration cadence |
withAccessLogDeliveryInterval(Duration) | S3 access-log delivery cadence |
withCorsAllowOrigins(List<String>) | Whole-server CORS (development) |
withRouter(HttpRouter) | Mount extra HTTP routes on the same port |
withAuthenticator(S3Authenticator) | Replace signature verification entirely |
withCredentialSource(CredentialSource) | Dynamic credential lookup (this is how IAM plugs in) |
withIdentityPolicies(IdentityPolicySource) | Per-identity policy enforcement |
withCryptoService(CryptoService) / withNoOpCrypto() | Encryption provider |
withCustomExecutor(ExecutorService) | Request executor (defaults to virtual threads) |
withFastETag() | Cheaper non-MD5 ETags |
withTestMode() | Enables test-only endpoints (_admin/nuke) |
withDisableAuthenticationForTesting() | Accept any request (tests only) |
Adding IAM
The tiny-s3-iam module provides the AWS IAM API and plugs into the builder via withCredentialSource / withIdentityPolicies — see how app's Application.java wires IamService for a complete example.
Notes
- Multipart upload state is tracked in memory regardless of storage backend.
- The server uses virtual threads by default; one instance handles many concurrent clients.
S3Server.stop()shuts down the listener and background schedulers.