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.

Intermediate 5 min read · Updated

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.

firstsecondthirdlastPrimary servicefailingService failed?1. Cached dataweather from 15 min ago2. Default valuepopular items3. Degraded modehide suggestions4. Placeholdergeneric image
When the primary service fails, try fallbacks in order: cached data first, then a safe default, then degraded mode, and a placeholder as the last resort.

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"]}
        raise

2. 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

FallbackUse whenExampleWatch out for
Cached dataA recent copy is still meaningfulWeather "updated 15 min ago"Data that goes stale fast (prices, balances)
Default valueNo usable cache; a safe generic answer existsPopular items instead of personalized onesDefaults that mislead (0 meaning free)
Degraded modeThe feature is optionalFeed without the suggestions sectionHiding something users rely on without explanation
PlaceholderLayout must stay intactGeneric product imageStubs that look like real data
Fail with a clear errorCorrectness matters more than availabilityPayment authorization, account balanceSlow failures: fail fast instead
Queue for laterThe work can happen after the responseSend the email when the provider recoversUnbounded 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.

UserProfile serviceCircuit breakerAchievementsGET /profileget badges?circuit OPEN: no call is madefallback: no badgesprofile without badgesafter 30 s: half-open trialtrial requestOK → circuit closes
Circuit open: the profile service skips the achievements call and returns the profile without badges; half-open trials decide when badges come back.

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

Netflix

When personalization is unavailable, rows fall back to popular or cached titles so the home screen always renders.

E-commerce

Reviews, recommendations and ads degrade independently; product, price and checkout are protected as the critical path.

CDNs and HTTP caches

stale-if-error and stale-while-revalidate serve cached pages when the origin is down.

Mobile apps

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.