Fallbacks and Graceful Degradation
Fallback strategies when a dependency fails: cached responses, safe defaults, graceful degradation and placeholders, and how they pair with circuit breakers.
A fallback is the alternative response a system gives when the primary operation fails. Circuit breakers stop calls to a failing service, but blocking a call on its own still leaves the user looking at an error page. Fallbacks let the system degrade gracefully instead of breaking: the user gets slightly less, not nothing.
Why fallbacks matter
A product page shows item details, reviews, recommendations and stock status. The reviews service goes down. Without fallbacks, the whole page errors: the customer can't see the product or buy it, even though everything needed to buy it works. One failed dependency has broken the entire feature.
With fallbacks, the page loads without reviews and shows "Reviews temporarily unavailable". The customer reads the details, checks stock and completes the purchase. Revenue keeps flowing; the experience is slightly worse but not broken.
Fallbacks turn catastrophic failures into minor inconveniences. Designing them forces a useful exercise: separating the critical path (product, price, checkout) from the nice-to-have features (reviews, recommendations, badges), so that non-critical failures never take down critical functionality.
1. Cached responses
The simplest fallback is data from an earlier successful call. Cache good responses with a timestamp; when the primary fails, return the cached copy along with how old it is.
A weather service normally fetches live data from an external API. When that API goes down, it returns the forecast from 15 minutes ago, labeled "Updated 15 min ago". Users still get useful information, because weather changes slowly enough for 15-minute-old data to be valuable.
- Match staleness to the domain. Stock prices change every second, so a 15-minute-old price is misleading: return an error instead. User profiles rarely change, so a day-old cached profile is a fine fallback.
- Choose cache lifetimes deliberately. A 5-minute cache for product prices balances freshness with fallback coverage; a 24-hour cache for user avatars both cuts load on the profile service and covers long outages.
- Serve stale on error. Many caches and CDNs can keep serving an expired entry when the origin fails (
stale-if-error). See cache invalidation.
def get_weather(city):
try:
data = weather_api.fetch(city, timeout=2)
cache.set(f"weather:{city}", {"data": data, "at": now()}, ttl=24 * 3600)
return {"data": data, "stale": False}
except (Timeout, ServiceError):
cached = cache.get(f"weather:{city}")
if cached and now() - cached["at"] < timedelta(hours=1): # still useful for weather
return {"data": cached["data"], "stale": True, "as_of": cached["at"]}
raise2. Default responses
When there's no cached data, or it's too old, return a safe default. The rule: a default must never mislead users or harm the business.
- Recommendations down → popular items. Instead of personalized suggestions, show the most popular products. They won't match the user's taste as well, but they're relevant, and something is better than an empty box.
- Discount calculator down → full price. For enterprise pricing, charge the full list price rather than guessing a discount. Full price is safe; applying a wrong discount loses money or breaks contracts. The conservative default protects the business.
Make defaults explicit. Don't return 0 or an empty string unless that genuinely means something. If the discount calculator falls back to 0, checkout might read it as "free". Return a flag or error code along with the default so callers know they are getting fallback data.
3. Graceful degradation
Turn off non-essential features when their backing services fail, so the core keeps working.
- Social feed. The feed shows friends' posts, trending topics and suggested accounts. If the suggestions service fails, hide that section; friends' posts and trends still appear.
- Video player. If the service that picks the best quality level fails, play in standard definition instead of failing playback. Watching the video matters more than optimizing it.
Tell users. A banner such as "Some features are temporarily unavailable" explains why things look different, so they can try later or contact support instead of being confused. See also load shedding, which degrades features on purpose when the system is overloaded.
4. Stubbed responses
Return placeholder data that keeps the UI's structure without real content, for cases where a gap would confuse users but real data isn't available.
- Product images. If the image service fails, show a generic product placeholder. The layout stays intact, and customers can still read the title and price and decide to buy. Missing photos are an annoyance, not a blocker.
- Dashboards. If the analytics service fails, keep the chart's frame and show "Data temporarily unavailable" inside it. The layout stays consistent, other charts still render, and users can check back later.
Stubs must be obviously stubs. A placeholder image should look generic, never like real product photography; users must not mistake fake data for real data.
Choosing a fallback
| Fallback | Use when | Example | Watch out for |
|---|---|---|---|
| Cached data | A recent copy is still meaningful | Weather "updated 15 min ago" | Data that goes stale fast (prices, balances) |
| Default value | No usable cache; a safe generic answer exists | Popular items instead of personalized ones | Defaults that mislead (0 meaning free) |
| Degraded mode | The feature is optional | Feed without the suggestions section | Hiding something users rely on without explanation |
| Placeholder | Layout must stay intact | Generic product image | Stubs that look like real data |
| Fail with a clear error | Correctness matters more than availability | Payment authorization, account balance | Slow failures: fail fast instead |
| Queue for later | The work can happen after the response | Send the email when the provider recovers | Unbounded backlogs |
Combining fallbacks with circuit breakers
The two work together. While the circuit is open, the system returns the fallback immediately, without even attempting the failing call, so no resources are wasted.
A user-profile service calls the achievements service for badges. Achievements fails repeatedly, and the circuit breaker opens. For the next 30 seconds, profile requests skip the achievements call entirely and return the profile without badges. Then the circuit goes half-open and lets a few test requests through. If achievements has recovered, badges reappear; if not, the circuit reopens and the fallback continues.
Fallbacks in interviews
For the system you're designing, say which services are critical and which can degrade, and describe what the user sees during each kind of failure. That shows you understand the difference between a catastrophic failure and acceptable degradation, which interviewers look for in senior candidates.
Where it’s used
When personalization is unavailable, rows fall back to popular or cached titles so the home screen always renders.
Reviews, recommendations and ads degrade independently; product, price and checkout are protected as the critical path.
stale-if-error and stale-while-revalidate serve cached pages when the origin is down.
Show the last synced data with an "offline" banner when the network or backend is unavailable. See offline-first sync.
In an interview
- Separate critical from non-critical dependencies and give each non-critical one a fallback.
- Prefer cached data, then safe defaults, then degraded mode, then placeholders, and say what the user sees.
- Choose conservative defaults (full price, "stock unknown") over ones that could mislead or lose money.
- Pair fallbacks with circuit breakers so an open circuit answers instantly.