Get in touch

Fill out this form and our team will respond as soon as we can, alternatively email us at mail@icepanel.io.

Back to all blogs

Design Strava using IcePanel

System design of Strava on IcePanel đź§Š

c4 modelsystem designtutorial
29 Jul 2026
Blog hero image

📝 Introduction

In this post, we’ll design Strava, a fitness tracking app that allows users to record and share their physical activities (e.g., running) with their friends. We’ll approach this problem as architects and design four hierarchical diagrams: Context, Container, Component, and Code (not familiar with these? Read this).

Each diagram will be annotated to explain the key building blocks and responsibilities, and we’ll highlight how users interact with the system by visualising data flow using IcePanel Flows.

We’ll start by defining the scope of the system through its functional requirements (what it should do) and non-functional requirements (the qualities it should have). From there, we’ll progressively go through each layer of the C4 model to build the overall architecture.

You can view the final architecture here: https://s.icepanel.io/DWnaysJ3cbCQqg/rveR


🔎 Scope

Strava is a popular fitness tracking app used by millions of runners and cyclists worldwide. It is also a social platform that has user feeds and regular events for users interested in participating.

For the scope of this post, we’ll narrow down the system to three functional requirements:

  1. Users should be able to start, pause, stop, and save their activities (i.e., runs).
  2. Users should be able to view their activity data (route, distance, and time).
  3. Users should be able to view their completed activities and their friends’ activities in a feed.

For a popular app like Strava, the system should have these non-functional requirements

Let’s start with the first diagram, Context.


Level 1 - Context

The Context layer defines the actors and systems Strava depends on. At this level, we treat Strava as a single system. However, the internal breakdown of mobile app vs backend comes at the Container level. For the Context layer, we have one actor called Runner. Runner is an end user who records activities (runs) through the Strava app.

We also have external systems that Strava depends on:

  1. Map Provider (Mapbox): Provides map tiles and route rendering for displaying activity routes through the Strava mobile app.
  2. Identity Provider (Auth0): Authenticates users via OAuth 2.0 and social login.

Level 1 - Context diagram

There are usually more external systems that integrate with Strava (e.g., wearable device APIs like Apple HealthKit for apple watch) but we’ll leave them outside of scope for this post.

The more detailed design comes next, which is the Container diagram.


Level 2 - Container

The Container layer zooms into the Strava system to show the services, apps, and data stores inside. A key architectural decision in this design is that most of the heavy lifting happens on the client (mobile app), not the backend. The client handles real-time GPS tracking, metric calculation, and offline support on-device. This means the backend can stay simple since it only receives completed activity data after a run is saved.

We don’t need a microservices architecture for this particular problem. Only 2 web servers (activity and feed builder) in the backend for handling activity data and user feed. We’ll talk more about the Components inside the mobile app as you’ll see in the deep dive below.

The Strava system contains the following containers:

Client

Backend

Level 2 - App diagram

On a high level, the system works as follows.

Write path: The user starts an activity. They record their GPS coordinates through their devices and cache them on the local storage temporarily. The Strava App uploads the complete GPS dataset to the API Gateway. The API Gateway routes it to the Activity Server, which stores the activity and route data in PostgreSQL, updates leaderboard Sorted Sets in Redis, and publishes a “new activity” event to SQS. The Feed Builder picks up the event, queries PostgreSQL for the user’s follower list, and writes the activity into each follower’s cached feed in Redis.

Read path: The user opens their feed. The API Gateway routes the request to the Feed Builder, which checks Redis for a cached feed. On a cache hit, it returns immediately. On a miss, it queries PostgreSQL, builds the feed, caches it in Redis, and returns the results.

We’ve designed two primary data flows using IcePanel. Check out these flows and play them step by step to see how our system works.

Flow 1: Start and save an activity
Complete flow: https://s.icepanel.io/DWnaysJ3cbCQqg/vkVU

  1. Runner starts an activity. Activity Manager triggers GPS Module.
  2. GPS Module captures coordinates and stores them in Local Storage every ~10 seconds.
  3. Metrics Module computes live stats (distance, pace, time) on-device from GPS data.
  4. Runner saves the activity. Activity Sync reads the complete dataset from Local Storage.
  5. Activity Sync uploads the GPS data via HTTP POST through API Gateway to Activity Server.
  6. Activity Server writes the activity and route data to Activity DB and updates leaderboard Sorted Sets in Redis.
  7. Activity Server publishes a “new activity” event to SQS.
  8. Feed Builder picks up the event, fetches the follower list from Activity DB, and writes the activity into each follower’s cached feed in Redis.

Flow 2: View leaderboard
Complete flow: https://s.icepanel.io/DWnaysJ3cbCQqg/7WZF

  1. Runner opens the leaderboard page in the Strava App.
  2. Activity Manager sends a GET request with query filters to Strava Backend.
  3. API Gateway routes the request to Activity Server.
  4. Activity API delegates to Leaderboard Manager.
  5. Leaderboard Manager queries the appropriate Redis Sorted Set (e.g., leaderboard:run:CA).
  6. Redis returns the top N ranked users.
  7. Activity Server returns the leaderboard data through API Gateway.
  8. Strava App renders the leaderboard.

Offline-first and GPS tracking

A key architectural consideration is offline support. Runners and cyclists frequently lose connectivity during activities (trails, rural roads, tunnels). The mobile app is designed to be offline-first for activity recording. GPS coordinates are captured and stored locally using the phone’s GPS hardware, which operates independently of network connectivity. All real-time metrics are calculated on-device. The upload only happens after the activity is saved and the device has connectivity.

The beauty of this design is that a complex backend isn’t needed. Modern smartphones have sensors, processing power, and local storage. For a system like Strava, the client plays a critical role in the overall design, enabling offline functionality, reducing server load, and improving user experience. The backend is primarily responsible for serving and storing data!


Level 3 - Component

In the C4 model, a component is a grouping of related modules encapsulated behind a well-defined interface. Let’s start with the components inside the Strava App. We’ll use iOS (Swift) for our examples, but the same concepts apply to Android.

Strava App (iOS/Android)

  1. Activity Manager: Coordinates the activity lifecycle and connects to GPS, metrics, auth, and map services.
  2. GPS Module: Captures GPS coordinates at regular intervals using device location services (Core Location on iOS, FusedLocationProviderClient on Android). Sends coordinates to Local Storage and to the Metrics Module.
  3. Metrics Module: Computes live stats on-device: distance, pace, and elapsed time from GPS data. Fetches GPS data from Local Storage and returns live metrics to the Activity Manager for display.
  4. Local Storage (SQLite): Persists GPS coordinates locally every ~10 seconds to avoid data loss.
  5. Activity Sync: Uploads completed activity data to the Strava backend when connectivity is available. The module reads the full GPS dataset from Local Storage and uploads it to the backend.

Level 3 - iOS Component diagram

Activity Server

The Activity Server handles the write path. Let’s look at its internal components.

  1. Activity API: Receives activity uploads, coordinates storage, and triggers leaderboard and feed updates.
  2. Database Client: Reads and writes user activities, routes, and GPS data to PostgreSQL.
  3. SQS Client: Publishes new activity events to SQS for async feed generation.
  4. Leaderboard Manager: Updates and queries leaderboard scores using Redis Sorted Sets.

Level 3 - Activity Component diagram

Feed Builder

The Feed Builder handles the read path and async fan-out. It has two entry points: synchronous feed requests from users, and async events from SQS.

  1. Feed API: Handles synchronous feed requests from users and delegates to the Feed Repository.
  2. SQS Consumer: Polls SQS for new activity events and triggers fan-out to follower feeds.
  3. Feed Repository: Fetches the user’s follower list and assembles the activity feed.
  4. Redis Client: Reads and writes cached friend feeds to Redis.
  5. Database Client: Queries follower/followee relationships and activity data from PostgreSQL.

Level 3 - Feed Component diagram

Let’s go one level deeper with the source code in the Code layer.


Level 4 - Code

This is where we can view implementation details at the code level. We’ll go over two components: Activity Server and Feed Builder.

Code Classes in Activity Server

This component handles all RESTful endpoints for activity management.

Activity API

Redis Client

Code Classes in Feed Builder

This component builds and serves friend feeds by polling SQS for new activities and caching results in Redis.

Feed API

Redis Client

Database Client

And these are some examples of interfaces that highlight the interactions within a Component in terms of code.


Conclusion

In this post, we designed a fitness tracking system like Strava using the C4 model on IcePanel. We began with the core requirements and modelled the system from the top down, starting with the Context layer, followed by the Container, Component, and finally the Code layer.

If you’re interested in more design deep dives, check out:

Let us know which system you’d like to see modeled next on IcePanel!

📚 Resources

Shehab

Get cool architecture news

Sign up for our free newsletter.

Stay chill

Get in touch

Fill out this form and our team will respond as soon as we can, alternatively email us at mail@icepanel.io.