In 2020 I published a dozen tutorials on this site covering Eureka, Hystrix, Zuul, Ribbon, and Feign — the Spring Cloud Netflix stack. They were accurate then. Today, most of that stack is dead: Netflix put Hystrix into maintenance mode back in 2018, Zuul 1 and Ribbon followed, and the Spring team removed them from the Spring Cloud release train entirely. If you are still running any of these libraries on Spring Boot 2.x, this guide maps every Netflix component to its modern replacement and shows you the actual migration steps — including the parts that break.
I keep the old tutorials online for teams maintaining legacy systems (each now carries a deprecation notice pointing here), but everything below targets Spring Boot 3.x/4.x and Spring Cloud 2025.x.
The Migration Map at a Glance
| Netflix Component | Status | Modern Replacement | Migration Effort |
|---|---|---|---|
| Hystrix (circuit breaker) | Maintenance mode since 2018, removed from Spring Cloud 2020.0 | Resilience4j via Spring Cloud CircuitBreaker | Medium — annotation model differs |
| Zuul 1 (API gateway) | Removed from Spring Cloud 2020.0 | Spring Cloud Gateway | High — blocking servlet model → reactive |
| Ribbon (client-side load balancing) | Removed from Spring Cloud 2020.0 | Spring Cloud LoadBalancer | Low — mostly transparent |
| Netflix Feign | Donated to OpenFeign community | Spring Cloud OpenFeign or HTTP interface clients | Low — package rename, or rewrite to @HttpExchange |
| Hystrix Dashboard / Turbine | Removed | Micrometer + Prometheus + Grafana | Medium — different mental model |
| Eureka (service discovery) | Still alive and maintained | Keep Eureka, or Kubernetes-native discovery | None / platform-dependent |
| Archaius (config) | Abandoned | Spring Cloud Config / Kubernetes ConfigMaps | Medium |
The single most important row in that table is Eureka. Teams often assume the whole Netflix stack died together — it did not. Eureka server and client are still actively maintained and ship in current Spring Cloud releases. If you are not on Kubernetes, there is no urgent reason to migrate off Eureka.
Why You Cannot Just Stay Put
The forcing function is the Spring Boot upgrade path. Spring Cloud Netflix modules (other than Eureka) only work with Spring Cloud Hoxton and older, which caps you at Spring Boot 2.3. Boot 2.x reached end of open-source support in 2023. Staying means no CVE patches for the framework underneath you. Every migration below is therefore really a sub-task of a Spring Boot 3 → 4 migration.
Hystrix → Resilience4j
This is the migration with the most code churn, because the programming model changed from command classes to annotations/decorators. The old way:
// BAD: Hystrix (maintenance mode since 2018)
@HystrixCommand(fallbackMethod = "fallbackStudents")
public List<Student> getStudents() {
return restTemplate.getForObject(STUDENT_URL, List.class);
}
And the modern equivalent:
// GOOD: Resilience4j (Spring Boot 3.x / 4.x)
@CircuitBreaker(name = "studentService", fallbackMethod = "fallbackStudents")
public List<Student> getStudents() {
return restClient.get().uri(STUDENT_URL)
.retrieve()
.body(new ParameterizedTypeReference<List<Student>>() {});
}
// Fallback signature MUST include the exception parameter,
// or Resilience4j silently ignores it — the #1 migration bug.
private List<Student> fallbackStudents(Throwable t) {
return List.of();
}
Key behavioural difference: Hystrix used thread-pool isolation by default; Resilience4j uses semaphore-based isolation and leaves threading to you. If you relied on Hystrix timeouts killing slow calls, you must now configure a TimeLimiter explicitly. Full setup, configuration table, and Actuator metrics are in the dedicated Resilience4j in Spring Boot guide.
Zuul → Spring Cloud Gateway
Zuul 1 was a blocking servlet filter chain; Spring Cloud Gateway is reactive (Netty + Project Reactor). That means your Zuul filters do not port line-by-line — ZuulFilter with filterType()/filterOrder() becomes GlobalFilter or per-route GatewayFilter returning Mono<Void>. Route definitions move from zuul.routes.* properties to spring.cloud.gateway.routes with predicates and filters. I cover the full filter-by-filter port, including the blocking-call traps, in the Zuul to Spring Cloud Gateway migration guide.
Ribbon → Spring Cloud LoadBalancer
The easiest migration of the lot. If you were using Ribbon indirectly (through @LoadBalanced RestTemplate, Feign, or Zuul), removing the Ribbon dependency and upgrading Spring Cloud is usually enough — spring-cloud-starter-loadbalancer takes over the same @LoadBalanced annotation:
@Bean
@LoadBalanced
RestClient.Builder loadBalancedRestClientBuilder() {
return RestClient.builder(); // service IDs like http://student-service now resolve via LoadBalancer
}
What does not carry over: custom Ribbon IRule implementations (zone-aware, weighted-response-time). Spring Cloud LoadBalancer ships only round-robin and random out of the box; anything fancier means implementing ReactorServiceInstanceLoadBalancer yourself.
Feign → OpenFeign → HTTP Interface Clients
Netflix Feign became OpenFeign years ago, and spring-cloud-starter-openfeign still works on Boot 3.x — a package rename (feign.* instead of com.netflix.feign.*) covers most of it. But the Spring team’s stated direction is the built-in HTTP interface clients (@HttpExchange), which need no extra starter on Boot 3.2+ and got first-class registration in Boot 4. If you are migrating anyway, skip a generation: my HTTP Service Clients guide shows the declarative interface approach, and the updated OpenFeign guide covers the halfway house.
Hystrix Dashboard → Micrometer Stack
There is no “dashboard replacement” — the model changed. Resilience4j publishes circuit-breaker state transitions, slow-call rates, and failure rates as Micrometer metrics; you scrape them with Prometheus and graph them in Grafana. If you have not set that stack up yet, start with my Prometheus & Grafana monitoring guide.
A Realistic Migration Order
From doing this on production systems, the order that minimises risk is: (1) Ribbon → LoadBalancer (low risk, unblocks the Spring Cloud upgrade), (2) Feign package migration, (3) Hystrix → Resilience4j service by service, (4) Zuul → Gateway last, because the gateway is the blast-radius component and the reactive rewrite needs the most testing. Trying to do all four in one release is how you end up rolling back at 2 a.m.
Frequently Asked Questions
Is Eureka deprecated? No. Eureka is the one Spring Cloud Netflix module still actively maintained and included in current release trains.
Can Hystrix and Resilience4j coexist during migration? Yes — they have no conflicting dependencies, so you can migrate one service (or one endpoint) at a time behind the Spring Cloud CircuitBreaker abstraction.
Do I need Spring Cloud at all on Kubernetes? Often not for discovery and config (Services and ConfigMaps cover it), but Resilience4j-style client-side resilience is still worth having — the platform cannot retry or short-circuit for you at the application-semantics level.
AI Prompts for This Migration
Audit Netflix Usage
Scan this Maven/Gradle dependency tree and codebase excerpt: [paste here]. List every Spring Cloud Netflix artifact in use (Hystrix, Zuul, Ribbon, Feign, Archaius, Turbine), where it is referenced in code, and map each to its modern replacement with estimated migration effort.
What it does: Produces a component-level migration inventory so you can size the work before committing to a release plan.
When to use it: At the start of a Boot 2 → 3/4 upgrade, before writing any code.
Convert Hystrix Commands
Convert this Hystrix-based class to Resilience4j annotations: [paste class here]. Preserve fallback behaviour, map hystrix.command timeout and threadpool settings to equivalent resilience4j.circuitbreaker / timelimiter / bulkhead YAML, and flag any behaviour that cannot be reproduced exactly.
What it does: Mechanical conversion plus an explicit list of semantic gaps (thread isolation, timeout behaviour) that need human review.
When to use it: Per-class during the Hystrix phase of the migration.
Port Zuul Filters
Rewrite this ZuulFilter as a Spring Cloud Gateway GlobalFilter: [paste filter here]. The result must be non-blocking; identify every blocking call (JDBC, RestTemplate, file I/O) and propose a reactive alternative or boundedElastic offload for each.
What it does: Handles the hardest part of the gateway migration — finding hidden blocking calls that will stall the Netty event loop.
When to use it: For each custom Zuul filter during the gateway phase.
Replace Custom Ribbon Rules
Here is my custom Ribbon IRule implementation: [paste here]. Implement the equivalent ReactorServiceInstanceLoadBalancer for Spring Cloud LoadBalancer, and explain any differences in how instance health is determined.
What it does: Bridges the one genuinely missing feature in the Ribbon migration — custom load-balancing strategies.
When to use it: Only if your audit found custom IRule/IPing classes; most projects can skip this.
Plan the Rollout
Given these services and their Netflix dependencies: [paste audit output here], produce a phased migration plan across N releases that keeps every service deployable at each step, with verification checks (metrics, smoke tests) per phase.
What it does: Turns the inventory into a release-by-release plan with rollback points.
When to use it: After the audit, when negotiating scope with your team or manager.
Conclusion
The Netflix stack served a generation of microservices well, but every component except Eureka is now a liability blocking your Spring Boot upgrade path. Migrate Ribbon and Feign first (cheap wins), Hystrix service-by-service, and Zuul last. Each linked guide above goes component-deep with working code.
See Also
- Resilience4j Circuit Breaker in Spring Boot
- Zuul to Spring Cloud Gateway Migration Guide
- Spring Boot 3 to 4 Migration Guide
- Spring Boot 4 HTTP Service Clients
- RestTemplate to RestClient Migration Guide
- Service Discovery with Eureka in Spring Boot 3.x