# CoApi ClientMode Configuration: Choosing Between REACTIVE, SYNC, and AUTO

> Understand CoApi ClientMode: REACTIVE, SYNC, and AUTO. Learn how to choose the best mode for your application to optimize performance and resource usage.

- Repository: [Ahoo Wang/coapi](https://github.com/ahoo-wang/coapi)
- Tags: deep-dive
- Published: 2026-02-23

---

**CoApi's `ClientMode` enum determines whether the framework instantiates non-blocking `WebClient` beans (REACTIVE), blocking `RestClient` beans (SYNC), or automatically infers the correct implementation (AUTO) by inspecting the classpath for Spring WebFlux classes.**

The `ahoo-wang/coapi` library abstracts HTTP client creation through the `ClientMode` configuration setting defined in [`ClientMode.kt`](https://github.com/ahoo-wang/coapi/blob/main/ClientMode.kt). This enum controls the underlying Spring HTTP client architecture, selecting between reactive and synchronous execution models. Choosing the correct mode ensures your API clients align with your application's threading model and performance requirements.

## How CoApi Uses ClientMode

CoApi delegates client instantiation to `CoApiRegistrar`, which examines the configured mode during Spring context initialization. In [`/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt), the `register()` method branches based on the `ClientMode` value to register either a `WebClientFactoryBean` or `RestClientFactoryBean`.

## REACTIVE Mode

When `ClientMode.REACTIVE` is specified, CoApi registers `WebClientFactoryBean` instances for all client interfaces. This creates non-blocking `WebClient` implementations suitable for Spring WebFlux applications.

Use **REACTIVE** mode when:

- Building applications on the Spring WebFlux reactive stack
- Requiring non-blocking I/O for high concurrency scenarios
- Working with `Mono` and `Flux` return types

The registration occurs in `CoApiRegistrar.register()` at [`/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt), specifically targeting the `WebClient` creation path.

## SYNC Mode

Setting `ClientMode.SYNC` forces CoApi to register `RestClientFactoryBean` beans, producing blocking `RestClient` implementations. This aligns with traditional Spring MVC servlet-based architectures.

Use **SYNC** mode when:

- Working with Spring MVC or servlet-based applications
- Calling legacy services from blocking codebases
- Preferring imperative programming models with direct return values

The synchronous path is handled in the same `register()` method, branching when `clientMode == ClientMode.SYNC`.

## AUTO Mode

**AUTO** is the default behavior. CoApi invokes `ClientMode.inferClientMode()` (defined in [`/spring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt)) to detect the web stack automatically:

```kotlin
private val INFERRED_MODE_BASED_ON_CLASS = try {
    Class.forName("org.springframework.web.reactive.HandlerResult")
    REACTIVE
} catch (e: ClassNotFoundException) {
    SYNC
}

```

This logic checks for the presence of `org.springframework.web.reactive.HandlerResult`. If found, CoApi assumes a WebFlux environment and selects REACTIVE; otherwise, it defaults to SYNC.

Use **AUTO** mode when:

- You want zero-configuration setup
- Your project clearly uses either WebFlux or MVC (but not both)
- You want CoApi to "just work" based on classpath inspection

You can override AUTO detection using the `coapi.mode` property defined in [`CoApiProperties.kt`](https://github.com/ahoo-wang/coapi/blob/main/CoApiProperties.kt).

## Practical Configuration Examples

### Forcing REACTIVE Mode

```yaml

# application.yml

coapi:
  mode: REACTIVE

```

```java
@Service
public class GitHubService {
    private final GitHubApi gitHubApi;
    
    // Injected WebClient-based implementation
    public GitHubService(GitHubApi gitHubApi) {
        this.gitHubApi = gitHubApi;
    }
}

```

### Forcing SYNC Mode

```yaml

# application.yml

coapi:
  mode: SYNC

```

```java
@Service
public class IssueService {
    private final IssueApi issueApi;
    
    // Injected RestClient-based implementation (blocking)
    public IssueService(IssueApi issueApi) {
        this.issueApi = issueApi;
    }
}

```

### Using AUTO (Default)

```yaml

# application.yml

coapi:
  # mode omitted - defaults to AUTO

```

No additional configuration required. CoApi inspects the classpath during startup via `AbstractCoApiRegistrar` and selects the appropriate factory.

## Summary

- **REACTIVE** mode instantiates `WebClientFactoryBean` for non-blocking WebFlux applications, registered through `CoApiRegistrar` in [`/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt)
- **SYNC** mode creates `RestClientFactoryBean` for blocking MVC applications using the same registration logic
- **AUTO** mode executes `inferClientMode()` in [`ClientMode.kt`](https://github.com/ahoo-wang/coapi/blob/main/ClientMode.kt) to detect WebFlux via `Class.forName("org.springframework.web.reactive.HandlerResult")`, defaulting to SYNC if absent
- Override automatic detection using the `coapi.mode` property constant defined in [`CoApiProperties.kt`](https://github.com/ahoo-wang/coapi/blob/main/CoApiProperties.kt)

## Frequently Asked Questions

### How does AUTO mode detect which client type to use?

AUTO mode calls `ClientMode.inferClientMode()` which attempts to load `org.springframework.web.reactive.HandlerResult` via reflection. If the class exists, CoApi assumes a WebFlux environment and selects REACTIVE; if a `ClassNotFoundException` occurs, it defaults to SYNC. This logic resides in [`/spring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/ClientMode.kt).

### Can I use REACTIVE mode in a Spring MVC application?

While technically possible, using REACTIVE mode in a Spring MVC application creates a mismatch between the blocking servlet threads and the non-blocking WebClient. This can lead to thread starvation or complex interoperability issues. CoApi allows explicit configuration via `coapi.mode=REACTIVE`, but you should ensure your calling code handles reactive types appropriately.

### What property overrides the AUTO detection?

The `coapi.mode` property (constant `COAPI_CLIENT_MODE_PROPERTY` in [`CoApiProperties.kt`](https://github.com/ahoo-wang/coapi/blob/main/CoApiProperties.kt)) accepts values of `REACTIVE`, `SYNC`, or `AUTO`. Set this in [`application.yml`](https://github.com/ahoo-wang/coapi/blob/main/application.yml) or as a JVM system property to bypass automatic inference.

### Where does CoApi register the actual client beans?

The `CoApiRegistrar.register()` method in [`/spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt`](https://github.com/ahoo-wang/coapi/blob/main//spring/src/main/kotlin/me/ahoo/coapi/spring/CoApiRegistrar.kt) performs the registration. It checks the `ClientMode` and instantiates either `WebClientFactoryBean` (REACTIVE) or `RestClientFactoryBean` (SYNC), both defined in their respective subpackages under `/spring/src/main/kotlin/me/ahoo/coapi/spring/client/`.