Feign vs RestTemplate vs WebClient
Fast recall
Quick revision
Core answer
Whether you can choose the right tool based on the runtime model (blocking vs reactive), and whether you know RestTemplate is deprecated in favour of WebClient/Feign
Using WebClient in a blocking servlet application 'for performance' without understanding that Reactor's subscribe/block in a Tomcat thread pool negates the non-blocking benefits and can actually cause thread starvation
Explain that OpenFeign integrates with Resilience4j via @CircuitBreaker, with Spring Cloud LoadBalancer for LB, and with Micrometer Tracing for automatic trace propagation — it's a one-stop declarative client. Mention that in Spring Boot 3.2+, the new RestClient is a synchronous alternative to WebClient with a similar fluent API.
Interview-ready guide
Interview answer
Three choices, each for a different situation. RestTemplate is synchronous, blocking, and in maintenance mode. Use it only in legacy code.
Feign is declarative — define an interface with @FeignClient, Spring generates the implementation. No boilerplate. It integrates with service discovery, circuit breakers, and tracing automatically. Best for standard service-to-service CRUD calls.
WebClient is non-blocking on Project Reactor. It doesn't tie up threads while waiting for responses. Use Mono.zip() to parallelize multiple HTTP calls without consuming threads. Best for high-concurrency scenarios.
The practical decision: if you're in a Spring MVC app with straightforward service calls, Feign is the cleanest. If you need non-blocking I/O or streaming, WebClient. RestTemplate only if you're maintaining existing code.
Don't call .block() on WebClient in WebFlux — it defeats the non-blocking model and can deadlock.
My recommendation: use Feign for straightforward service-to-service calls and WebClient when you need non-blocking I/O or concurrent request fan-out.
Feign vs RestTemplate vs WebClient
Direct Answer
Feign is a declarative HTTP client for synchronous, readability-first inter-service calls — ideal with Spring Cloud and Eureka. RestTemplate is the legacy synchronous HTTP client being deprecated. WebClient is the non-blocking, reactive choice for high-concurrency scenarios or reactive stacks. In new synchronous Spring Boot services, Feign wins for simplicity; for reactive services, WebClient wins.
Code Example
Calling GET /api/orders/{id} on order-service (resolved through service discovery), with a POST /api/orders alongside. Same behaviour; four dramatically different surfaces.
1. Feign — declarative interface, Spring Cloud integrated:
@FeignClient(name = "order-service", path = "/api/orders")
public interface OrderClient {
@GetMapping("/{id}")
Order getOrder(@PathVariable("id") String orderId);
@PostMapping
@CircuitBreaker(name = "order-service", fallbackMethod = "createFallback")
Order createOrder(@RequestBody CreateOrderRequest req);
default Order createFallback(CreateOrderRequest req, Throwable t) {
return Order.queuedForRetry(req);
}
}
@Service
class OrderUsage {
private final OrderClient client;
public Order fetch(String id) { return client.getOrder(id); }
public Order create(CreateOrderRequest r) { return client.createOrder(r); }
}
No URL construction, no response-type gymnastics, no manual exchange(). Service discovery, load balancing, circuit breaker, tracing propagation all wired by the presence of their starters on the classpath.
2. RestTemplate — legacy, still works, imperative:
@Configuration
class ClientsConfig {
@Bean @LoadBalanced
RestTemplate restTemplate(RestTemplateBuilder b) {
return b.connectTimeout(Duration.ofSeconds(2))
.setReadTimeout(Duration.ofSeconds(5))
.build();
}
}
@Service
class OrderUsage {
private final RestTemplate rt;
public Order fetch(String id) {
return rt.getForObject("http://order-service/api/orders/{id}", Order.class, id);
}
public Order create(CreateOrderRequest r) {
return rt.postForObject("http://order-service/api/orders", r, Order.class);
}
}
Verbose. No built-in circuit breaker — you wrap calls yourself with @CircuitBreaker on the caller or use Resilience4j programmatically. Deprecated since Spring 5.3 in favour of RestClient/WebClient.
3. WebClient — reactive, non-blocking:
@Configuration
class ClientsConfig {
@Bean @LoadBalanced
WebClient.Builder webClientBuilder() { return WebClient.builder(); }
}
@Service
class OrderUsage {
private final WebClient wc;
OrderUsage(WebClient.Builder b) {
this.wc = b.baseUrl("http://order-service").build();
}
public Mono<Order> fetch(String id) {
return wc.get().uri("/api/orders/{id}", id)
.retrieve().bodyToMono(Order.class);
}
public Mono<Order> create(CreateOrderRequest r) {
return wc.post().uri("/api/orders")
.bodyValue(r)
.retrieve().bodyToMono(Order.class)
.transformDeferred(CircuitBreakerOperator.of(orderCircuitBreaker));
}
// Concurrent fan-out — three services in parallel, zero extra threads
public Mono<Dashboard> dashboard(String userId) {
return Mono.zip(
wc.get().uri("/api/orders/user/{id}", userId).retrieve().bodyToFlux(Order.class).collectList(),
inventoryClient.forUser(userId),
recommendationClient.forUser(userId))
.map(t -> new Dashboard(t.getT1(), t.getT2(), t.getT3()));
}
}
The Mono.zip fan-out is the real payoff — three concurrent HTTP calls without three blocked threads. In a WebFlux stack this scales to thousands of concurrent requests per replica.
4. RestClient (Spring Boot 3.2+) — synchronous but fluent, WebClient's better twin for MVC:
@Configuration
class ClientsConfig {
@Bean @LoadBalanced
RestClient.Builder restClientBuilder() { return RestClient.builder(); }
}
@Service
class OrderUsage {
private final RestClient rc;
OrderUsage(RestClient.Builder b) {
this.rc = b.baseUrl("http://order-service").build();
}
public Order fetch(String id) {
return rc.get().uri("/api/orders/{id}", id)
.retrieve().body(Order.class);
}
public Order create(CreateOrderRequest r) {
return rc.post().uri("/api/orders")
.body(r)
.retrieve().body(Order.class);
}
}
Fluent like WebClient, synchronous like RestTemplate, no Reactor knowledge required. Modern choice for Spring MVC projects that don't want Feign's Spring Cloud dependency chain.
Quick picking table:
| Situation | Use |
|---|---|
| Spring Cloud stack, simple CRUD calls to other services | Feign |
| Spring MVC, no Spring Cloud, need modern fluent API | RestClient |
| WebFlux app, OR concurrent fan-out in MVC via bounded-context reactive islands | WebClient |
| Existing RestTemplate code, no urgent reason to migrate | RestTemplate (but plan migration) |
| New code | Never RestTemplate |
Common Mistakes & Pitfalls
Using WebClient in a blocking servlet application 'for performance' without understanding that Reactor's subscribe/block in a Tomcat thread pool negates the non-blocking benefits and can actually cause thread starvation
Check your understanding
Answer these without looking back at the article.
- How do you configure timeouts and retries on a Feign client?
- How does Feign integrate with Resilience4j circuit breaker?
- What is Spring Boot 3.2's RestClient and how does it differ from WebClient?
Related interview prep categories
2Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.