Arconia Dev Services

Arconia Dev Services streamline your development workflow by automatically provisioning external services your application depends on during development and testing. No manual setup is required.

Need a database, message broker, or other infrastructure components for your application? Add the corresponding Dev Service dependency to your project. When you run your application or tests, the required services start automatically as OCI containers and are seamlessly wired into your application. Zero additional code or configuration needed.

Built on Testcontainers and Spring Boot’s Testcontainers support, Arconia Dev Services provide a great developer experience by eliminating the friction of manually setting up and managing services in your development environment.

Dev Services are designed exclusively for development and testing workflows. They are excluded from production builds and have zero impact on your production deployments.

How It Works

When Arconia Dev Services are detected during development or testing, the framework:

  1. Starts the container: Launches an OCI container for the required service using Testcontainers.

  2. Configures the connection: Sets up connection properties (URLs, credentials, ports).

  3. Wires the service: Integrates the service into your application context using Spring Boot’s Service Connection mechanism.

  4. Manages the lifecycle: Handles container startup, shutdown, and cleanup.

This happens transparently without requiring any code or configuration. Dev Services take precedence over manually configured properties, ensuring your application always connects to the containerized service during development and testing.

Quick Start

Get started with Arconia Dev Services in three simple steps:

  1. Add the dependency for your required service (e.g., PostgreSQL):

    • Gradle

    • Maven

    dependencies {
        testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql'
    }
    <dependency>
        <groupId>io.arconia</groupId>
        <artifactId>arconia-dev-services-postgresql</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
  2. Run your application as usual:

    • Gradle

    • Maven

    • CLI

    ./gradlew bootRun
    ./mvnw spring-boot:run
    arconia dev
  3. That’s it! The PostgreSQL container starts automatically and your application connects to it. No configuration files, no code changes needed.

Want to verify which Dev Services are running? If Spring Boot Actuator is in your classpath, check the /actuator/devservices endpoint.

Using Dev Services

Dev Services are available as separate modules for each supported service. You can find the complete list in the Supported Services section below.

Dev Services are provisioned as OCI containers. Ensure you have a container runtime like Podman or Docker installed and running in your environment.

Service Connections

Your application is automatically configured to connect to Dev Services, which take precedence over manually configured properties. For example, when using the arconia-dev-services-postgresql module, the Dev Service transparently overrides properties like spring.datasource.url, spring.datasource.username, and spring.datasource.password.

The auto-configuration mechanism uses Spring Boot’s Service Connections internally to establish connections between your application and containerized services, eliminating the need for manual property configuration or test-specific setup code.

Lifecycle Management

Arconia instructs Spring Boot to manage the lifecycle of Dev Services as beans in the application context:

  • Startup: Services start when the application context initializes.

  • Shutdown: Services stop when the context closes.

  • Persistence: Services remain available throughout the lifecycle of your application or tests.

When using Spring Boot DevTools, Dev Services are not recreated on restart. They remain running in the background, ensuring a smooth development experience without wait times or state loss.

Configuration Options

Each Dev Service can be customized through Spring Boot configuration properties. All Dev Services support a common set of properties under the arconia.dev.services.<service-name> prefix.

Common Properties

The following properties are available for all Dev Services.

All Dev Services are enabled by default. Other properties have sensible defaults that may vary by service.

Property Description

arconia.dev.services.<service-name>.enabled

Whether the dev service is enabled.

arconia.dev.services.<service-name>.image-name

Full name of the container image used in the dev service.

arconia.dev.services.<service-name>.environment

Environment variables to set in the service.

arconia.dev.services.<service-name>.network-aliases

Network aliases to assign to the dev service container.

arconia.dev.services.<service-name>.port

Fixed port for exposing the primary service port to the host. When it’s 0 (default), a random available port is assigned dynamically.

arconia.dev.services.<service-name>.resources

Resources from the classpath or host filesystem to copy into the container. They can be files or directories that will be copied to the specified destination path inside the container at startup and are immutable (read-only).

arconia.dev.services.<service-name>.shared

Whether the dev service is shared among applications. Only applicable in dev mode.

arconia.dev.services.<service-name>.startup-timeout

Maximum waiting time for the service to start.

arconia.dev.services.<service-name>.volumes

Files or directories to mount from the host filesystem into the container. They are mounted at the specified destination path inside the container at startup and are mutable (read-write). Changes in either the host or the container will be immediately reflected in the other.

Service-Specific Properties

Individual services provide additional configuration properties. Refer to each service’s documentation for all available configuration options.

Sharing Dev Services

Dev Services can be shared across multiple applications during development, allowing you to reuse the same containerized service for multiple projects running simultaneously. This is particularly useful for:

  • Distributed systems: Share a message broker (e.g., RabbitMQ, Kafka) or observability platform (e.g. Grafana LGTM) across multiple services.

  • Resource efficiency: Avoid running duplicate containers for the same service, especially for resource-intensive services (e.g., Docling, Ollama).

To enable/disable sharing for a specific Dev Service, you can set the arconia.dev.services.<service-name>.shared property. By default, sharing is enabled only for services where it makes sense, such as message brokers, observability platforms, and resource-intensive services.

Sharing Dev Services is only supported when running the application in dev mode. When running automated tests, Dev Services are never shared to ensure test isolation, consistency, and reliability.

Pre-Requisites for Container Sharing

Container sharing relies on the Reusable Containers feature of Testcontainers, which is disabled by default. To enable it:

  1. Create or edit the file ~/.testcontainers.properties in your home directory

  2. Add the following line:

testcontainers.reuse.enable=true

Once enabled, shared Dev Services will persist across application restarts and can be reused by other applications.

Reusable containers will not be automatically removed when no longer needed. You must stop and remove them manually using your container runtime (Docker/Podman) when they are no longer required.

Resource Mappings

Dev Services support copying files and directories from your classpath or host filesystem into the container at startup. This can be useful for various scenarios, including for loading configuration files, seeding initialization data, or making static resources available to containerized services.

Resources are copied to the specified destination path inside the container at startup and are never changed on the host after being copied (read-only). This means that any modifications made by the container to these files will not persist or affect the source files on the host.

This strategy is preferred over mounting host directories as volumes, as it avoids potential issues with file permission mismatches, path resolution, and cross-platform compatibility.

Configuration

Resource mappings are configured through the arconia.dev.services.<service-name>.resources property. Each mapping requires two values:

  • Source path: Location of the resource on the classpath or filesystem;

  • Container path: Destination path inside the container.

For example, to copy a configuration file from the classpath into an OpenTelemetry Collector container:

arconia:
  dev:
    services:
      otel-collector:
        resources:
          - source-path: otel-collector-config.yml
            container-path: /etc/otelcol-contrib/config.yaml

Source Path Resolution

The source path supports multiple resolution strategies:

  • Automatic resolution: Without a prefix, Arconia first attempts to locate the resource on the classpath. If not found, it searches the filesystem. For example, config/database.conf will be resolved from the classpath if available, otherwise from the filesystem.

  • Explicit classpath: Use the classpath: prefix to load resources from the classpath. For example, classpath:config/database.conf.

  • Explicit filesystem: Use the file: prefix to load resources from the host filesystem. For example, file:./config/database.conf.

Using explicit prefixes (classpath: or file:) improves clarity and readability, making it clear where the resource is being loaded from. It also avoids ambiguity and potential resolution issues, especially in complex projects with multiple resource locations.

Volume Mappings

Dev Services support binding files and directories from the host filesystem into the container at startup. This can be useful for various scenarios, including for persisting data generated by the containerized service or for sharing files between your host and the container.

Files or directories specified in the volume mappings are mounted from the host filesystem into the container at the specified destination path inside the container at startup and are mutable (read-write). Changes in either the host or the container will be immediately reflected in the other.

Since this provides direct read-write access between the host and container, use this feature with caution. Ensure that the mounted paths are secure and do not expose sensitive data or system files. Furthermore, be aware of potential file permission issues that may arise due to differences between the host and container environments.

It’s recommended to use volume mappings only when necessary. Instead, consider using resource mappings for most use cases where read-only access is sufficient.

Configuration

Volume mappings are configured through the arconia.dev.services.<service-name>.volumes property. Each mapping requires two values:

  • Host path: Location of the file or directory on the host filesystem;

  • Container path: Destination path inside the container.

For example, to mount a configuration directory from the host filesystem into a PostgreSQL container:

arconia:
  dev:
    services:
      postgresql:
        volumes:
          - host-path: ./postgresql/data
            container-path: /var/lib/postgresql/data/pgdata

Networks and Ports

Dev Service containers are connected to the default Docker/Podman network and are accessible from your application via the local host and dynamically assigned ports.

Fixed Ports

By default, Dev Services use random available ports to avoid conflicts. However, you can configure fixed exposed ports when needed. Each service supports the arconia.dev.services.<service-name>.port property to specify a fixed port for exposing the primary service provided by the container.

Some Dev Services may expose multiple ports (e.g., management console ports). In such cases, the Dev Service will offer additional properties to configure fixed ports for those secondary services. For example, the RabbitMQ Dev Service provides the common arconia.dev.services.rabbitmq.port property for the main AMQP port and an additional arconia.dev.services.rabbitmq.management-console-port property for the management UI port.

A common use case for fixed ports is when other tools or services in your development environment need to connect to the Dev Service container using a known port, or for exposing UI consoles through well-known ports. For example, to expose Grafana on port 3000.

Using fixed ports may cause conflicts if another service is already using the port. Consider using fixed ports only when necessary.

Startup Sequence

Control how Dev Services start using the spring.testcontainers.beans.startup property. It can be set to parallel or sequential. By default, Dev Services are started sequentially.

Global Configuration

In case you want to disable all Dev Services at once, you can set the arconia.dev.services.enabled property to false.

Disabling Dev Services globally overrides individual service settings. If global disabling is set, no Dev Services will start, regardless of their individual enabled properties. If you want to disable only specific services, leave the global setting enabled and configure individual services instead via the arconia.dev.services.<service-name>.enabled property.

Actuator

When running the application in dev mode, a devservices actuator endpoint is auto-configured if Spring Boot Actuator is present in the classpath. This endpoint exposes information about the running Dev Services containers, helping you inspect and debug your development environment.

Usage

List All Dev Services

Retrieve information about all running Dev Services:

http :8080/actuator/devservices

Response example:

{
  "docling": {
    "name": "docling",
    "description": "Docling Dev Service",
    "containerInfo": {
      "id": "dbbda8272b5dc8d2ccfa48d3723756d767eef727322d9c35e0fd4c44ba60e967",
      "imageName": "ghcr.io/docling-project/docling-serve:latest",
      "exposedPorts": [
        {
          "ip": "0.0.0.0",
          "privatePort": 5001,
          "publicPort": 45525,
          "type": "tcp"
        }
      ]
    }
  },
  "postgresql": {
    "name": "postgresql",
    "description": "PostgreSQL Dev Service",
    "containerInfo": {
      "id": "cbf5a15cf5420eddd2daf0e912256b140c0ad067f9329f425a2ecdaa01008bc5",
      "imageName": "docker.io/pgvector/pgvector:latest",
      "exposedPorts": [
        {
          "ip": "0.0.0.0",
          "privatePort": 5432,
          "publicPort": 36803,
          "type": "tcp"
        }
      ]
    }
  }
}

Get Details for a Specific Dev Service

Retrieve detailed information about a specific Dev Service:

http :8080/actuator/devservices/postgresql

Response example:

{
  "name": "postgresql",
  "description": "PostgreSQL Dev Service",
  "containerInfo": {
    "id": "cbf5a15cf5420eddd2daf0e912256b140c0ad067f9329f425a2ecdaa01008bc5",
    "imageName": "docker.io/pgvector/pgvector:latest",
    "names": [
      "/unwritten_mithrandir"
    ],
    "exposedPorts": [
      {
        "ip": "0.0.0.0",
        "privatePort": 5432,
        "publicPort": 36803,
        "type": "tcp"
      }
    ],
    "labels": {
      "org.testcontainers.lang": "java",
      "org.testcontainers": "true"
    },
    "status": "Up About 67 minutes"
  }
}

The endpoint provides visibility into container IDs, image names, port mappings, and other runtime information useful for troubleshooting and debugging.

Arconia Dev Services vs. Spring Boot Development-time Services

Arconia Dev Services is a higher-level abstraction built on top of Spring Boot’s Testcontainers support. While both approaches leverage Testcontainers for provisioning services, Arconia Dev Services provides a more streamlined, zero-configuration experience.

Key Differences

The primary distinction is simplicity. Arconia Dev Services eliminates boilerplate code and configuration, allowing you to focus on development rather than infrastructure setup.

  • Arconia Dev Services

  • Spring Boot Development-time Services

dependencies {
    testAndDevelopmentOnly 'io.arconia:arconia-dev-services-postgresql'
}

Run your application normally:

./gradlew bootRun
dependencies {
    testAndDevelopmentOnly 'org.springframework.boot:spring-boot-testcontainers'
    testAndDevelopmentOnly 'org.testcontainers:postgresql'
}

Create a test configuration class:

@TestConfiguration(proxyBeanMethods = false)
public class TestContainersConfiguration {

    @Bean
    @ServiceConnection
    @RestartScope
    PostgreSQLContainer<?> postgresContainer() {
        return new PostgreSQLContainer<>("postgres:latest");
    }
}

Create a test main class:

public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.from(Application::main)
            .with(TestContainersConfiguration.class)
            .run(args);
    }
}

Run from the test classpath:

./gradlew bootTestRun

Import the Testcontainers configuration in each test class needing the service:

@SpringBootTest
@Import(TestContainersConfiguration.class)
class ApplicationTests {
}

Migration Path

If your project already uses Spring Boot’s Testcontainers support, you can adopt Arconia Dev Services incrementally:

  1. Add Arconia dependencies for services you want to manage automatically.

  2. Keep existing Testcontainers configuration for custom or unsupported services.

  3. Gradually migrate more services to Arconia as needed.

Both approaches work alongside each other, allowing smooth transitions without disrupting your workflow.

Feature Comparison

Aspect Arconia Dev Services Spring Boot Development-time Services

Dependencies

Single dependency per service.
Example: arconia-dev-services-postgresql.

Multiple dependencies per service.
Example: spring-boot-testcontainers + testcontainers-postgresql.

Code Requirements

Zero additional code required

Requires:
@TestConfiguration class with @Bean methods;
• Test main class with SpringApplication.from();
@ServiceConnection and @RestartScope annotations.

Configuration

Declarative via application.yml properties.
Example: arconia.dev.services.postgresql.startup-timeout=30s.

Programmatic configuration in Java code when defining container beans.

Application Startup

Standard commands:
./gradlew bootRun
./mvnw spring-boot:run
arconia dev

Special test classpath commands:
./gradlew bootTestRun
./mvnw spring-boot:test-run
arconia dev --test

Integration Testing

Automatic service discovery and wiring: no imports or annotations needed.

Requires explicit @Import(TestContainersConfiguration.class) or similar mechanism.

DevTools Live Restart

Automatic persistence across restarts: containers survive application reloads.

Requires @RestartScope annotation on each container bean definition.

Service Sharing

Declarative via properties:
arconia.dev.services.<name>.shared=true.

Manual configuration when defining container beans with withReuse(true).

Customization

Configuration properties for common scenarios.
Example: image-name, port, init-script-paths.

Full programmatic control. Direct access to Testcontainers API in bean definitions.

Flexibility

Opinionated with sensible defaults. Configuration properties are available for common use cases.

Maximum flexibility. Full control over container lifecycle and configuration.

Learning Curve

Minimal
Add dependency → Run application

Moderate
Requires understanding of Testcontainers API, Spring Boot integration patterns, and test classpath execution.

Best For

Rapid development, standard use cases, teams seeking simplicity.

Advanced scenarios requiring custom container configuration or specialized setups