Sitemap

Design Dropbox / Google Drive / Cloud Storage | System Design Interview #03 — by Sheel

18 min readOct 3, 2026

--

Chapter 03 of System Design Interview Series

In this series, I am covering the most asked system design interview questions in a way that focuses on how you should actually answer the interviewer.

If you haven’t watched Chapter 02 yet, check it out: Chapter 02

In this article, we’ll design a system like Google Drive/Dropbox

Press enter or click to view image in full size

✦ The Interview Starts ✦

Interviewer: Design a cloud file-storage and synchronization system like Dropbox.

Candidate: Sure. Before jumping into the architecture, I’d like to first clarify the requirements.

I’ll assume that the actual blob storage system is already available, so I won’t design something like Amazon S3 from scratch.

Does that scope sound good?

Interviewer: Yes. Go ahead.

1. Functional Requirements

Candidate: The three main functional requirements are:

1. Upload a file: A user should be able to upload a file from their device to remote storage.

2. Download a file: A user should be able to download a previously uploaded file.

3. Synchronize files across devices: If a file changes on one device, the change should eventually appear on the user’s other connected devices.

For example:

Laptop
│
│ Upload / Modify
▼
Remote Storage
│
├──────────► Phone
│
└──────────► Desktop

So if I add resume.pdf to my Dropbox folder on my laptop, it should eventually appear on my desktop and phone as well.

Press enter or click to view image in full size

Interviewer: Anything out of scope?

Candidate: Yes. I’ll keep the scope focused.

Out of scope:

  • Building our own blob storage
  • File sharing between users
  • Collaboration/editing
  • File version history

We can discuss those if you’d like to extend the requirements later.

2. Non-Functional Requirements

Now I’d move to the non-functional requirements.

For this system, I’d prioritize:

➣High availability: Users should be able to access their files even if part of the system is unavailable.

➣High data integrity: Eventually, the local folder and remote storage should represent the same state. A small amount of temporary inconsistency is acceptable.

➣Low upload/download latency: We should minimize the time required to transfer files.

➣Large file support: Let’s assume we need to support files as large as 50 GB.

➣Resumable uploads: If a user uploads a 50 GB file and their internet disconnects after 30 GB, they shouldn’t have to start again from zero.

➣Eventual consistency: For example, if I modify a file in Germany and immediately open it in the US, it’s acceptable if the US device sees the previous version for a short period.

But eventually, all devices should converge to the same state.

Interviewer: Why are you choosing availability over consistency?

Candidate: Because this is primarily a file-access and synchronization system.

I’d rather allow a user to download an older version for a few seconds than completely prevent them from accessing their files because one replica hasn’t caught up yet.

So under a network partition, I’d prioritize:

Availability → over immediate consistency

while still maintaining strong data integrity once the system stabilizes.

3. Scale Estimation

Interviewer: What scale are you designing for?

Candidate: I’d assume a Dropbox-scale system with hundreds of millions of daily active users (DAU).

The most important scaling characteristics here are:

  • Very large number of users
  • Very large storage requirements
  • Large file sizes
  • High upload/download bandwidth
  • Globally distributed users

For raw file storage, I’ll use horizontally scalable blob storage such as S3.

I’ll do detailed calculations later if a specific design decision requires them.

💡 Interview Tip

Don’t perform calculations just because system design interviews are supposed to have “back-of-the-envelope estimation.”

A useful estimation is one that changes your design. That’s a useful calculation.

4. Core Entities

Now let’s identify the major objects in our system. I don’t need the entire database schema yet.

At this stage, I just want to understand what information exists.

We’ll have:

▶File:The actual bytes of the uploaded file. We’ll store these in blob storage.

▶FileMetadata

Information about the file:

file_id
file_name
mime_type
size
owner_id
created_at
updated_at
storage_location
status

▶User:The owner of the files.

Press enter or click to view image in full size

Note: MIME type tells us what kind of content the client claims to upload.

Examples:

image/jpeg
image/png
application/pdf
video/mp4

Suppose our application only accepts images. We can say:

Allowed:
image/jpeg
image/png

and reject unsupported types.

5. API Design

Now let’s map our functional requirements to APIs.

Initially, I’ll keep these APIs simple and refine them later once we understand the architecture.

▶ Upload

POST /files

Request:

{
"file": "...",
"metadata": {
"name": "resume.pdf",
"mimeType": "application/pdf",
"size": 5242880
}
}

Response:

{
"fileId": "f123"
}

▶ Download

GET /files/{fileId}

Response:

File + metadata

▶ Get Changes

For synchronization:

GET /changes?since={timestamp}

Response:

{
"changes": [
{
"fileId": "f123"
},
{
"fileId": "f456"
}
]
}

The client can then download those files.

👨‍💼 Interviewer: How do you know which user is making the request?

👨‍💻 Candidate: I wouldn’t trust the client to send a userId in the request body.

Instead, authentication information would come through something like:

Authorization: Bearer <JWT>

or a session token.

The API Gateway authenticates the user and passes the authenticated identity to downstream services.

That prevents a malicious client from simply changing:

{
"userId": "someone-else"
}

and accessing another user’s files.

6. High-Level Architecture

Now that we have the requirements and APIs, let’s build the architecture.

Press enter or click to view image in full size

7. Uploading a File

Interviewer: Walk me through what happens when a user uploads a file.

👨‍💻 Candidate

In our initial design:

  1. Client sends the file to the File Service.
  2. File Service stores the actual bytes in blob storage.
  3. Blob storage returns the storage location.
  4. File Service stores the metadata in the metadata database.
  5. We return success to the client.

Like this:

Press enter or click to view image in full size

But there’s an important problem here.This design is okay for small files.

It is not good enough for 50 GB files. And that’s where we need to improve it.

8. Large File Upload Problem

Interviewer: What’s wrong with this design for a 50 GB file?

👨‍💻 Candidate: There are two major problems.

▶ Problem 1 — Duplicate bandwidth

The file travels:

Client
↓
File Service
↓
S3

We’re unnecessarily sending 50 GB through our application servers.

That wastes:

  • Network bandwidth
  • CPU
  • Server resources

▶ Problem 2 — Request size limits

API gateways, browsers, and servers generally impose request-body limits.

So sending a 50 GB file inside one HTTP request isn’t practical.

Therefore, we should never route the actual large file through our application servers.

9. Pre-Signed URLs

Instead, we’ll use a pre-signed URL.

▶ First understand the problem

A user wants to upload:

vacation.jpg

There are two servers involved:

Client              Our Server              S3
| | |
|---- upload file --->| |
| |---- upload file -->|
| | |
| | |

The simplest design is:

Client → File Service → S3

The client sends the actual file to our backend.

▶ What’s wrong with this?

Imagine the file is 500 MB.

The data travels:

Client
|
| 500 MB
↓
File Service
|
| 500 MB
↓
S3

Our File Service has to receive and then forward 500 MB.

If 10,000 users upload files simultaneously:

10,000 users
|
↓
File Service
|
↓
S3

Our server becomes a bottleneck.

It needs:

  • lots of bandwidth
  • lots of network capacity
  • more servers
  • more CPU/memory for handling connections
  • potentially higher infrastructure cost

So we want:

Client ─────────────────────→ S3
file

But there’s a problem:

We don’t want to give the client our S3 credentials.

This is where pre-signed URLs come in.

▶ What is a pre-signed URL?

Think of a pre-signed URL as a temporary permission slip.

For example, imagine a hotel gives you a card:

“This person is allowed to enter Room 205 until 5 PM.”

The card itself gives you temporary access.

Similarly, our server can generate a URL saying:

“This client is allowed to upload this particular file to this particular S3 location until 10:35:30.”

For example:

https://my-bucket.s3.amazonaws.com/
uploads/user123/photo.jpg
?X-Amz-Algorithm=...
&X-Amz-Credential=...
&X-Amz-Expires=300
&X-Amz-Signature=abc123...

That long URL contains authentication/signature information.

The client doesn’t need to know the actual AWS secret key.

▶ The important idea

A pre-signed URL is basically:

A normal S3 URL + a temporary cryptographic signature that proves the server authorized a specific operation.

So instead of giving the client:

AWS_ACCESS_KEY
AWS_SECRET_KEY

we give it:

TEMPORARY PRE-SIGNED URL

▶ Let’s understand the flow step-by-step

Suppose I want to upload:

cat.jpg

Step 1 — Client asks our server

The client first says:

POST /files/upload

with metadata:

{
"fileName": "cat.jpg",
"contentType": "image/jpeg",
"size": 5000000
}

We’re only saying: “I want to upload this file.”

▶ File Service checks the request

Our File Service can check:

Is the user logged in?
↓
Is this user allowed to upload?
↓
Is file size allowed?
↓
Is MIME type allowed?
↓
Generate unique object name

For example:

uploads/user123/8f7a2c-cat.jpg

This is important because we don’t necessarily want users controlling arbitrary S3 object paths.

▶ File Service generates the pre-signed URL

“File Service” is our own backend microservice. It isn’t an AWS service.

Our backend has AWS credentials.

For example:

File Service
|
| AWS credentials
↓
S3

The backend asks AWS: “Give me temporary permission to upload an object at this specific location.”

For example:

Bucket: my-files
Object: uploads/user123/8f7a2c-cat.jpg
Operation: PUT
Expiration: 5 minutes

S3/AWS generates a signed URL. Something conceptually like:

https://my-files.s3.amazonaws.com/uploads/user123/8f7a2c-cat.jpg?expires=300&signature=XYZ

The exact URL is much longer in reality.

▶ File Service gives the URL to the client

Our backend responds:

{
"uploadUrl": "https://my-files.s3.amazonaws.com/...."
}

Now the client has temporary permission.

▶ Client uploads directly to S3

Now comes the most important part. The client uses that URL:

Client
|
| PUT file
| using pre-signed URL
↓
S3

The 50 MB file does NOT go through our File Service.

It goes directly:

CLIENT ─────────────────────→ S3
cat.jpg

This is the major benefit.

▶ Why is this called “pre-signed”?

Because the URL was signed before the client used it.

Think of it like a signed permission slip.

Our backend essentially says:“I authorize this request.”

AWS can verify the signature.

If the signature is valid:

✅ Valid signature
✅ Not expired
✅ Correct request
↓
Allow

If somebody modifies the URL or tries to use it incorrectly:

❌ Invalid signature
↓
Reject

The new flow becomes:

Client
│
│ 1. Send metadata
▼
File Service
│
│ 2. Generate pre-signed URL
▼
Blob Storage
│
│ 3. Return signed URL
▼
Client
│
│ 4. Upload directly
▼
Blob Storage

The File Service only handles authorization and metadata.

The actual file transfer happens directly between:

Client ↔ Blob Storage

👨‍💼 Interviewer: Why can’t we simply make S3 publicly writable?

👨‍💻Candidate: That would be a security problem.

Anyone with access could potentially upload arbitrary content.

Instead, our server generates a short-lived pre-signed URL with restrictions such as:

  • Allowed object
  • Allowed MIME type
  • Allowed size
  • Expiration time
  • Upload permissions

The client can use that URL temporarily without having direct S3 credentials.

Press enter or click to view image in full size

10. Resumable Uploads

Now we still have another problem. Imagine a user uploads a 50 GB file.

At 100 Mbps, that upload can take a long time. What happens if the network disconnects after 30 GB?

We don’t want:

30 GB uploaded ❌
Internet disconnected
↓
Restart from 0 GB

Instead, we’ll use chunking.

11. Chunking

The client splits the file into smaller pieces.

For example:

50 GB File
┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
│ 5 MB │ │ 5 MB │ │ 5 MB │ │ 5 MB │ ...
└──────┘ └──────┘ └──────┘ └──────┘

Each chunk can be uploaded independently.

If the connection fails:

Chunk 1 ✔
Chunk 2 ✔
Chunk 3 ✔
Chunk 4 ✔
Chunk 5 ❌
Chunk 6 ❌

We only retry:

Chunk 5
Chunk 6
...

instead of restarting the entire file.

Press enter or click to view image in full size

12. Fingerprinting Chunks

Interviewer: How do you know whether a particular chunk was already uploaded?

Get Sheel Ganvir’s stories in your inbox

Join Medium for free to get updates from this writer.

Candidate: We can use fingerprinting.

For every chunk, we calculate a hash:

chunk bytes
│
▼
SHA-256
│
▼
fingerprint

That fingerprint becomes the unique identifier for that chunk.

For example:

Chunk A → hashA
Chunk B → hashB
Chunk C → hashC

The metadata system can store:

chunk_id
fingerprint
status
storage_location

When the client resumes an upload, it compares its local chunk fingerprints with the server-side metadata.

If a fingerprint is already marked as successfully uploaded, we skip it.

13. Tracking Chunk Status

Our metadata might now look something like:

{
"fileId": "file123",
"name": "movie.mp4",
"size": 53687091200,
"status": "uploading",
"chunks": [
{
"fingerprint": "abc123",
"status": "uploaded",
"storageLocation": "..."
},
{
"fingerprint": "def456",
"status": "uploaded",
"storageLocation": "..."
},
{
"fingerprint": "ghi789",
"status": "pending"
}
]
}

The database could be SQL or NoSQL depending on the rest of the system.

For this design, I would use a NoSQL database such as DynamoDB because we’re frequently accessing file metadata and chunk state using identifiers such as file ID. The actual files would be stored in S3, while DynamoDB would store metadata and upload state.

MongoDB can also work here. I would choose DynamoDB because our access patterns are mostly key-based lookups for file IDs, upload IDs, and chunk IDs, and we’re already using AWS S3. DynamoDB gives us a managed, highly scalable key-value store that fits this workload. If the existing system already uses MongoDB or requires more flexible document queries, MongoDB would also be a reasonable choice.

14. Trust but Verify

Interviewer: The client uploads a chunk to S3. How does your metadata database know that the chunk was actually uploaded?

Candidate:

One naive approach would be:

Client → S3
↓
Success
Client → File Service
↓
"Chunk uploaded successfully"

But I don’t want to blindly trust the client. A malicious or buggy client could send incorrect information.

Instead, I’d use a trust-but-verify approach.

Client
│
│ Upload chunk
▼
S3
│
│ Success
▼
Client
│
│ Notify File Service
▼
File Service
│
│ Verify
▼
S3
│
│ Confirm
▼
Metadata DB
│
└── Mark chunk = uploaded

Now our metadata reflects what actually exists in blob storage.

Press enter or click to view image in full size

15. Downloading a File

Interviewer: How would downloading work?

Candidate:

The client sends:

GET /files/{fileId}

The File Service looks up the metadata.

The metadata contains the blob-storage location.

Instead of downloading the file through our application server, we can return a secure download URL.

Then:

Client
│
│ Request file
▼
File Service
│
│ Get metadata
▼
Metadata DB
│
│
▼
Pre-signed Download URL
│
▼
Client ─────────────► S3
│
▼
File bytes

Again, our application servers don’t become the bottleneck for transferring huge files.

Press enter or click to view image in full size

Note: The File Service generates both the pre-signed upload URL and the pre-signed download URL using its AWS permissions. The client then communicates directly with S3 for the actual file transfer.

16. Automatic Synchronization

Now we reach the most interesting part of the system. How do we keep multiple devices synchronized?

Our client isn’t just a simple browser. We have a client application installed on the user’s machine.

It manages:

Local Folder
│
▼
Client Application
│
├── Local DB
│
└── Remote Sync Service

The client needs to handle two directions:

Remote → Local: Something changed remotely.

Local → Remote: Something changed locally.

Press enter or click to view image in full size

17. Remote → Local Sync

Suppose I change a file on my laptop. My desktop needs to discover that change.

One simple approach is polling.

The client periodically asks:

GET /changes?since=timestamp

The server checks which files changed after that timestamp.

For example:

Last sync: 10:00 AM
Current time:10:05 AMChanged files:
resume.pdf
project.zip
photo.jpg

The client downloads those changes.

18. Local → Remote Sync

Suppose you have:

~/Dropbox/resume.pdf

and you edit/save the file.

The Dropbox app needs to notice that the file changed.

The operating system provides a file watcher that can monitor a folder.

The flow is:

You edit resume.pdf
↓
OS detects file changed
↓
Dropbox client notices
↓
Client uploads changed file/chunks
↓
S3 stores the new data
↓
Database updates metadata

The Dropbox client watches the local folder using OS file-system APIs; whenever a file changes, it detects the change and starts the upload/sync process.

The important point is that the client application is continuously watching the local Dropbox folder, rather than repeatedly asking the server, “Did my file change?”

19. Local Database

Interviewer: How does the client know whether it has already downloaded a file?

Candidate: I’d maintain a small local database.

For example:

Local DB

file_id
local_path
fingerprint
updated_at

This allows the client to compare:

Remote State
↕
Local DB
↕
Local File System

We can use fingerprints to determine whether two chunks/files represent the same content.

20. Making Sync Faster

Now let’s think about synchronization latency.

Our first approach is polling.

👨‍💼 Interviewer: Why not use WebSockets?

👨‍💻 Candidate: WebSockets are possible, but I don’t think they’re necessary here. The product doesn’t necessarily require millisecond-level synchronization.

If the file appears on another device within a few seconds, that’s generally sufficient.

Maintaining persistent connections for every connected device would introduce additional infrastructure and operational complexity.

So I’d start with adaptive polling.

For example:

Normal activity → poll every 30 seconds

Active folder → poll more frequently
No activity → poll less frequently

We can also provide a manual Refresh option.

21. Delta Sync

There’s another major optimization.

Suppose I have a 50 GB file. I modify only a small portion of it.

Do we really want to download the entire 50 GB file again?

No.

We can use delta synchronization.

Instead of transferring the entire file:

50 GB File
↓
Changed chunks only
↓
Client

For example:

Chunk 1 ✔ unchanged
Chunk 2 ✔ unchanged
Chunk 3 ❌ changed
Chunk 4 ✔ unchanged
Chunk 5 ✔ unchanged

Only Chunk 3 needs to be transferred.

The client can then reconstruct the updated file locally.

Press enter or click to view image in full size

22. How Should We Detect Changes?

We have two main options.

▶ Option 1 — Poll the Database

The client asks: “Give me all changes for folder X after timestamp Y.”

The database returns the changed files/chunks.

▶ Option 2 — Event Bus + Cursor

Instead of the client repeatedly asking the database “Did anything change?”, we keep a stream of change events using something like Kafka.

Suppose a file changes:

resume.pdf changed
↓
Kafka / Event Bus
↓
Event #1051

The client remembers the last event it received:

Cursor = 1050

Next time, it asks: “Give me all events after 1050.”

Kafka gives:

Event #1051 → resume.pdf changed
Event #1052 → photo.jpg changed
Event #1053 → notes.txt changed

The client processes them and moves its cursor to:

Cursor = 1053

Why is this useful?

If the client goes offline, it can later say: “My last processed event was #1050. Give me everything after that.”

So it doesn’t miss changes.

In simple words:

Kafka keeps a sequence of file-change events, and the cursor tells the client where it stopped. When it reconnects, it continues from that point.

👨‍💼 Interviewer: Which one would you choose?

👨‍💻 Candidate: For the requirements we’ve defined, I’d start with database polling.

An event bus with cursors is powerful, but it introduces additional complexity.

If the requirements included:

  • File version history
  • Audit trails
  • Rollbacks
  • Event replay

then I’d be much more interested in the event-stream approach.

But since our current requirements don’t include those features, I’d prefer the simpler design.

23. Reconciliation

Even with a good synchronization mechanism, things can go wrong.

For example:

  • Client crashes
  • Network failures
  • Metadata inconsistency
  • Application bugs
  • Partial uploads
  • Corrupted local state

So I’d introduce a periodic reconciliation process.

The client periodically compares:

Remote State
│
│ compare
▼
Local DB
│
│ compare
▼
Local Files

If something doesn’t match, we repair it.

For example:

Remote:
A ✔
B ✔
C ✔

Local:
A ✔
B ❌
C ✔

The reconciliation process detects that B is inconsistent and downloads the correct version.

This gives us a safety net beyond normal synchronization.

Press enter or click to view image in full size

But how is Reconciliation different from the Remote → Local polling that we discussed earlier?

The main difference is purpose.

Remote → Local polling

Polling asks: “What has changed remotely since my last check?”

For example:

Client
│
│ "Any new changes?"
↓
Server / DB
│
↓
A changed
B changed
│
↓
Client downloads A, B

It’s part of the normal synchronization process.

Reconciliation

Reconciliation asks: “Is my local state actually correct?”

It compares the states:

Remote:  A ✓  B ✓  C ✓
Local: A ✓ B ✗ C ✓
↓
Something is wrong
↓
Repair B

It’s a periodic safety check.

Example: Imagine the client successfully downloaded B.pdf, but then the local file became corrupted.

Normal polling might say: “There are no new remote changes.”

So it does nothing.

Reconciliation later compares:

Remote B.pdf → version 5 / hash XYZ
Local B.pdf → version 5 / hash ABC

It realizes:

“The versions look the same, but the content doesn’t match.”

Then it repairs the local file.

So remember:

Polling keeps you updated. Reconciliation makes sure you’re actually correct.

24. Improving Upload & Download Latency

We’ve already improved uploads significantly with chunking.

Why?

Because multiple chunks can potentially be uploaded in parallel.

Instead of:

Chunk 1 → Chunk 2 → Chunk 3 → Chunk 4

we can potentially do:

Chunk 1 ─┐
Chunk 2 ─┤
Chunk 3 ─┼──► S3
Chunk 4 ─┤
Chunk 5 ─┘

This helps us make better use of the available network bandwidth.

We can also adapt chunk sizes based on network conditions.

25. Should We Use a CDN?

👨‍💼 Interviewer: Would you add a CDN?

👨‍💻 Candidate:

Potentially, but I wouldn’t add one automatically.

A CDN is useful when content is frequently accessed by geographically distributed users.

For example:

User Germany
↓
CDN Germany
↓
Cached File

But in a personal file-storage system, users mostly access their own files.

So the cache-hit ratio may not justify the additional cost and complexity.

If our requirements later include heavily shared files with millions of downloads, then a CDN becomes much more attractive.

26. Compression

Another optimization is compression.

For files like:

TXT
JSON
CSV
DOCX

compression can significantly reduce the number of bytes transferred.

But files like:

JPEG
PNG
MP4

are often already compressed.

Compressing them again may provide little benefit while adding CPU overhead.

So compression can be decided intelligently based on:

  • File type
  • File size
  • Network conditions
  • CPU cost

27. Final Architecture

After all these improvements, our system looks roughly like this:

Press enter or click to view image in full size

28. Let’s Correct Our Initial APIs

Remember when we started?

We initially had:

POST /files

with the entire file in the request. Now we know that’s not what we actually want. Our API needs to reflect the architecture we’ve designed.

Step 1 — Initialize Upload

POST /files

Request:

{
"name": "video.mp4",
"size": 53687091200,
"mimeType": "video/mp4"
}

Response:

{
"fileId": "file123",
"uploadUrl": "https://storage/...signed..."
}

Step 2 — Upload Chunks

The client uploads chunks directly to the pre-signed URL / multipart-upload mechanism.

Client
│
├── Chunk 1 ──► S3
├── Chunk 2 ──► S3
├── Chunk 3 ──► S3
└── Chunk 4 ──► S3

Step 3 — Update Metadata

The system records the status of uploaded chunks.

{
"fileId": "file123",
"chunks": [
{
"fingerprint": "abc",
"status": "uploaded"
},
{
"fingerprint": "def",
"status": "uploaded"
}
]
}

Step 4 — Synchronization API

GET /changes?folderId=123&since=cursor

The response can contain enough metadata for the client to determine what it needs to download.

29. Interview-Level Summary

👨‍💼 Interviewer: Give me a quick summary of your final design.

👨‍💻 Candidate:

Sure.

I’d design the system around three core requirements: upload, download, and synchronization.

For file metadata, I’d use a scalable database, while the actual file bytes would live in blob storage such as S3.

For large files, I wouldn’t send the bytes through our application servers. Instead, the File Service would generate pre-signed URLs, allowing the client to upload directly to blob storage.

To support files as large as 50 GB and provide resumable uploads, the client would split files into chunks. Each chunk would have a fingerprint so we can determine which chunks have already been uploaded.

For synchronization, we’d have a client application with a local database and filesystem watcher. Remote changes can be detected using adaptive polling, while local changes trigger uploads.

To reduce synchronization bandwidth, we’d use delta sync, transferring only changed chunks rather than entire files.

Finally, we’d periodically perform reconciliation to make sure the local and remote states eventually converge.

The system prioritizes availability and data integrity, while allowing short periods of eventual consistency.

⭐ What the Interviewer Is Actually Looking For

The architecture is important. But the way you communicate it is equally important.

A strong system design answer doesn’t sound like: “We’ll use Kafka, Redis, Kubernetes, S3 and DynamoDB.”

Instead, it sounds like: “We have a problem with large files. Sending them through our API servers wastes bandwidth and also hits request-size limits. So I’ll move the data path directly from the client to blob storage using pre-signed URLs.”

The Interview Flow You Should Remember

For a Dropbox-like system, your mental flow should be:

                    REQUIREMENTS
│
▼
CORE ENTITIES
│
▼
APIs
│
▼
HIGH-LEVEL DESIGN
│
▼
FIND BOTTLENECKS
│
┌──────────┼───────────┐
▼ ▼ ▼
Large Files Sync Latency
│ │ │
▼ ▼ ▼
Chunking Polling Parallel
+ Fingerprint Delta Upload
+ Resume Sync + Compression
│ │ │
└──────────┼───────────┘
▼
DATA INTEGRITY
│
▼
RECONCILIATION

Now you are ready to design Dropbox / Cloud Storage

🔔 One last thing

If you haven’t subscribed yet, subscribe so you don’t miss the upcoming articles in this series. In the next articles, we’ll take another common system design interview problem and break it down the same way.

If you found this article helpful, don’t forget to share it with your friends who are also preparing.

If you liked my efforts and want to support

You can connect me on:

LinkedIn | Medium | Github | X | YouTube | Instagram | Email

Got doubts or suggestions? Drop them in the comments.

I notice every comments :)

--

--

Sheel Ganvir
Sheel Ganvir

Written by Sheel Ganvir

Software Engineer | Writing some free stuffs which can be valuable!!