Getting started
Requirements#
- Java 21 or later. Halyx uses virtual threads for parallel transfers and message listeners.
- The Halyx provider modules for the clouds you use. Each brings its cloud's SDK.
- For Spring Boot applications, Spring Boot 3.5 or 4.
Add the dependencies#
Import the BOM so every Halyx module has the same version, then add the core API and the providers you need:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.halyx</groupId>
<artifactId>halyx-bom</artifactId>
<version>1.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.halyx</groupId>
<artifactId>halyx-core</artifactId>
</dependency>
<dependency>
<groupId>dev.halyx</groupId>
<artifactId>halyx-aws</artifactId> <!-- and/or halyx-azure, halyx-gcp, halyx-vault -->
</dependency>
</dependencies>
Gradle (Kotlin DSL):
dependencies {
implementation(platform("dev.halyx:halyx-bom:1.1.0"))
implementation("dev.halyx:halyx-core")
implementation("dev.halyx:halyx-aws") // and/or halyx-azure, halyx-gcp, halyx-vault
}
Gradle (Groovy):
dependencies {
implementation platform('dev.halyx:halyx-bom:1.1.0')
implementation 'dev.halyx:halyx-core'
implementation 'dev.halyx:halyx-aws' // and/or halyx-azure, halyx-gcp, halyx-vault
}
| Module | What it adds |
|---|---|
halyx-core |
The portable API, error model, interceptors and an in-memory provider. No cloud SDKs. |
halyx-aws |
Amazon S3, DynamoDB, SNS, SQS, EventBridge, Lambda, SSM Parameter Store, Secrets Manager, ElastiCache and RDS IAM login |
halyx-azure |
Blob Storage, Cosmos DB, Service Bus, Event Grid namespaces, Azure Functions, Key Vault, App Configuration, and Entra ID login for caches and databases |
halyx-gcp |
Cloud Storage, Firestore, Pub/Sub, Eventarc Advanced, Cloud Run functions, Secret Manager, Parameter Manager, and IAM login for Memorystore and Cloud SQL |
halyx-vault |
HashiCorp Vault KV v2 parameters and secrets |
halyx-reactor |
Mono and Flux views of every service, for Reactor, WebFlux and other reactive code (see Reactive and async code) |
halyx-micrometer |
Micrometer observations of every operation, and trace context carried through messages, events, stream records and function invocations, without Spring (see Errors, retries and interceptors) |
halyx-spring-boot-starter |
Spring Boot auto-configuration (see Spring Boot) |
Providers are discovered with ServiceLoader: a module on the classpath is all it takes. SQL databases
also need your JDBC driver (org.postgresql:postgresql, com.mysql:mysql-connector-j or
com.microsoft.sqlserver:mssql-jdbc).
On the module path, the jars are automatic modules named after their root packages: dev.halyx for
halyx-core, dev.halyx.aws, dev.halyx.azure, dev.halyx.gcp, dev.halyx.jdbc for halyx-sql, and
dev.halyx.spring for the auto-configuration. Write requires dev.halyx; and requires dev.halyx.aws;.
Providers are found through their META-INF/services files, as they are on the classpath.
Your first calls#
A Halyx object holds one named connection per cloud account or region. It is thread-safe, meant to
live as long as the application, and closes every client it opened:
try (Halyx halyx = Halyx.builder()
.register("orders", ProviderConfig.of("aws").region("eu-west-2"))
.build()) {
CloudContext aws = halyx.provider("orders");
BlobStore invoices = aws.blobStore("acme-invoices");
invoices.put(BlobKey.of("invoices/42.pdf"), BlobContent.ofFile(Path.of("42.pdf")),
PutOptions.builder().contentType("application/pdf").ifNotExists().build());
try (Blob blob = invoices.get(BlobKey.of("invoices/42.pdf"))) {
blob.content().transferTo(response.getOutputStream());
} catch (NotFoundException e) {
// the same exception on S3, Azure Blob Storage and Cloud Storage
}
}
Credentials come from each cloud's default chain unless you pass them: environment variables, workload identity (EKS, AKS, GKE), instance or managed identity, or your CLI login. A provider can also assume an AWS IAM role, impersonate a Google service account, or log in to Azure as an Entra ID service principal. See Provider configuration for credentials, regions, endpoints and every setting.
Use several clouds at once#
Register one provider per cloud, or several per cloud, and use each by name:
Halyx halyx = Halyx.builder()
.register("aws", ProviderConfig.of("aws").region("eu-west-2"))
.register("azure", ProviderConfig.of("azure").property(AzureProperties.STORAGE_ACCOUNT, "acmefiles"))
.register("gcp", ProviderConfig.of("gcp").property(GcpProperties.PROJECT_ID, "acme-prod"))
.build();
BlobStore reports = halyx.provider("azure").blobStore("reports"); // Azure Blob Storage
Cache<String> sessions = halyx.provider("aws").cache(sessionCacheConfig); // ElastiCache
Publisher events = halyx.provider("gcp").publisher("order-events"); // Pub/Sub
Test without a cloud#
The memory provider implements object storage, NoSQL, messaging, caches, and parameters and secrets in
memory, with the same semantics the conformance kits check on the real services. It is ideal for unit
tests (SQL databases need a real database, for example in a Testcontainers container):
Halyx halyx = Halyx.builder().register("test", ProviderConfig.of("memory")).build();
BlobStore store = halyx.provider("test").blobStore("any-bucket");
For integration tests, point a provider at an emulator with ProviderConfig.endpoint(...), for example
LocalStack or Floci for AWS.
With Spring Boot#
Add halyx-spring-boot-starter and a provider module, describe your resources in application.yml,
and inject them:
halyx:
providers:
aws: { type: aws, region: eu-west-2 }
blob-stores:
invoices: { bucket: acme-invoices }
@Service
class InvoiceService {
InvoiceService(BlobStore invoices) { ... }
}
The Spring Boot page covers every resource type, listeners, health and metrics.
Next steps#
- API guide: every service in depth.
- Errors and retries: handling failures the same way on every cloud.
- Capabilities and native clients: provider-specific features.
- Plain Java quickstart: a complete runnable example without Spring.