MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
File Storage with S3
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

File Storage with S3

Reading50 min

Any backend with user-uploaded content eventually needs a place to put files that isn't your own server's disk. Interviewers use S3 to check something deeper than "can you call boto3.upload_file()": whether you understand consistency guarantees and failure handling in a managed service you don't fully control. This lesson covers presigned URLs, multipart upload for large files, what S3's consistency model actually guarantees today, and how to handle its failure modes.

Why not upload through your own server

Picture a delivery company where every package first gets driven to the company's own office, unpacked, and re-shipped to the warehouse, instead of going straight to the warehouse. That's what happens when a client uploads a file to your API and your API forwards it to S3: you pay for the bandwidth twice, and an app server or worker sits tied up for the entire upload, doing nothing but relaying bytes.

The standard pattern instead: your server hands the client a presigned URL, the client uploads directly to S3 using it, and your server never touches the file's bytes at all.

Python
import boto3
from botocore.config import Config

s3 = boto3.client(
    "s3",
    region_name="us-east-1",
    config=Config(signature_version="s3v4"),
)

def generate_upload_url(bucket: str, key: str, content_type: str, expires_in: int = 300) -> str:
    return s3.generate_presigned_url(
        ClientMethod="put_object",
        Params={"Bucket": bucket, "Key": key, "ContentType": content_type},
        ExpiresIn=expires_in,  # seconds — keep short; a leaked URL is a temporary write hole
    )
Python
from fastapi import FastAPI
from pydantic import BaseModel
import uuid

app = FastAPI()

class UploadRequest(BaseModel):
    filename: str
    content_type: str

@app.post("/uploads/presign")
async def presign_upload(req: UploadRequest, current_user=Depends(get_current_user)):
    # namespace the key by user and a random suffix — never trust the client's filename directly
    key = f"uploads/{current_user.id}/{uuid.uuid4()}-{req.filename}"
    url = generate_upload_url("my-bucket", key, req.content_type)
    return {"upload_url": url, "key": key}

The client then does a plain PUT to upload_url with the file bytes and the matching Content-Type header. No AWS credentials ever touch the client. The presigned URL only authorizes the exact operation, bucket, key, and content type it was generated for; a client can't reuse it to write to a different key or with a different content type, S3 rejects the mismatch outright.

Remember: a presigned URL lets the client upload directly to S3 with no AWS credentials of its own, and only for the exact bucket, key, and content type it was signed for.

Sign in to try this knowledge check.

Multipart upload for large files

Above roughly 100MB, AWS's own recommendation for where multipart starts paying off, and required above 5GB, split the upload into parts uploaded independently. That enables parallelism and lets a single failed part be retried without redoing the whole file.

Python
def start_multipart_upload(bucket: str, key: str) -> str:
    response = s3.create_multipart_upload(Bucket=bucket, Key=key)
    return response["UploadId"]

def presign_part_url(bucket: str, key: str, upload_id: str, part_number: int, expires_in: int = 3600) -> str:
    return s3.generate_presigned_url(
        ClientMethod="upload_part",
        Params={
            "Bucket": bucket,
            "Key": key,
            "UploadId": upload_id,
            "PartNumber": part_number,  # 1-indexed, up to 10,000 parts
        },
        ExpiresIn=expires_in,
    )

def complete_multipart_upload(bucket: str, key: str, upload_id: str, parts: list[dict]) -> None:
    # parts: [{"ETag": "...", "PartNumber": 1}, {"ETag": "...", "PartNumber": 2}, ...]
    # ETags come back from each part's PUT response — the client must collect and report them
    s3.complete_multipart_upload(
        Bucket=bucket,
        Key=key,
        UploadId=upload_id,
        MultipartUpload={"Parts": sorted(parts, key=lambda p: p["PartNumber"])},
    )

def abort_multipart_upload(bucket: str, key: str, upload_id: str) -> None:
    # ALWAYS clean up on failure — abandoned multipart uploads still count against storage billing
    s3.abort_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id)

The full flow: the server calls create_multipart_upload to get an UploadId, presigns one URL per part, the client uploads each part directly, in parallel, retrying any that fail individually, the client reports back each part's ETag, and the server calls complete_multipart_upload. If anything goes wrong, call abort_multipart_upload. S3 keeps charging for incomplete multipart parts left sitting around, which is exactly why bucket lifecycle rules typically include an "abort incomplete multipart uploads after N days" policy as a safety net.

Remember: multipart upload lets one failed part get retried without redoing the whole file. Always set a lifecycle rule to abort abandoned multipart uploads; S3 bills for them even if they never complete.

Sign in to try this knowledge check.

S3's consistency model

Historically, S3 offered only eventual consistency for overwrite PUTs and deletes, meaning a GET right after an overwrite or a delete could briefly return stale data, while a brand-new object's first PUT was always strongly consistent. As of December 2020, AWS made all S3 operations strongly read-after-write consistent: a GET immediately after any successful PUT or DELETE now reflects that change. This is a genuinely popular interview trivia question because it overturned a widely known "fact" about S3. Know the current behavior, strong consistency, but also be able to explain what eventual consistency means in general, a write succeeds, but a read right afterward might not reflect it yet, converging eventually, since interviewers sometimes use S3 only as an example while really testing the general concept.

One consistency question still matters operationally, though: a CDN in front of S3 (CloudFront) still serves stale content until its cache invalidates or its TTL expires. That's a real staleness window you have to design around, versioned object keys instead of overwriting, or an explicit cache invalidation on update, regardless of what S3 itself guarantees underneath.

Remember: S3 has been strongly read-after-write consistent for every operation since December 2020. A CDN sitting in front of it is a separate staleness source you still have to design around.

Sign in to try this knowledge check.

Handling S3 failures

Python
import time
from botocore.exceptions import ClientError, EndpointConnectionError

def upload_with_retry(bucket: str, key: str, body: bytes, max_attempts: int = 4) -> None:
    for attempt in range(1, max_attempts + 1):
        try:
            s3.put_object(Bucket=bucket, Key=key, Body=body)
            return
        except ClientError as exc:
            error_code = exc.response["Error"]["Code"]
            if error_code in ("SlowDown", "ServiceUnavailable", "InternalError"):
                # transient — retry with exponential backoff
                if attempt == max_attempts:
                    raise
                time.sleep(2 ** attempt)
                continue
            # NoSuchBucket, AccessDenied, etc. — permanent, don't retry
            raise
        except EndpointConnectionError:
            if attempt == max_attempts:
                raise
            time.sleep(2 ** attempt)

Categorize S3 errors the same way you'd categorize any external dependency's errors. Transient errors, SlowDown (you're being throttled), ServiceUnavailable, network blips, get retried with backoff. Permanent errors, AccessDenied, NoSuchBucket, InvalidArgument, fail immediately, since retrying changes nothing about the outcome. SlowDown specifically means you've exceeded S3's request-rate limit for that key prefix; the fix beyond backoff is spreading keys across more prefixes, since S3 scales its request rate partly by how spread out your prefixes are.

For presigned-URL uploads specifically, there's a different failure mode: the client's direct PUT to S3 can fail without your server ever finding out, since your server was never in that request path. The standard mitigation is having the client explicitly report completion back to your API, or having your server verify the object exists with head_object before trusting that an upload actually finished.

Remember: retry transient errors like SlowDown with backoff; fail immediately on permanent errors like AccessDenied. For presigned uploads, your server only learns an upload succeeded if the client reports it, or your server checks with head_object.

Sign in to try this knowledge check.
PreviousDocker and ContainersNextTesting Strategies

Course progress

0%
0 of 177 modules complete

On this page

  • Why not upload through your own server
  • Multipart upload for large files
  • S3's consistency model
  • Handling S3 failures