Week 9

Types of Databases

Databases: Comparison, Choosing & Polyglot

jsonb: Concepts & Setup

jsonb: querying updating

jsonb: Indexes, Tradeoffs & Exercise

Object Storage

Practice

Assignment

Backend Track

Storing large files

You know how to store text and numbers in PostgreSQL. But what about files, profile pictures, uploaded CVs, invoices, or exported reports?

Storing files in a database is possible but almost always the wrong choice. Another solution can be storing files on the server’s storage (SSD or Hard drive). But this can be very tricky in a world of Docker containers and distributed applications - your application may run on multiple servers in parallel. A different type of storage was built specifically for files: object storage.


1. What is Object Storage?

Object storage is a system designed specifically for storing files - photos, PDFs, videos, zip files. Think of it as a giant filing cabinet in the cloud where you put a file in, give it a name, and retrieve it later by that name.

You access everything through a simple HTTP API - upload with PUT, download with GET. No SQL, no tables.

image.png

Object storage has no real folders. avatars/user-42.jpg is just a string with a slash in it -there is no actual folder called avatars. This simplicity is what lets it scale to billions of files.


2. Object Storage vs Database vs Filesystem

Object Storage Database (PostgreSQL) Filesystem
Best for Large binary files Structured data Local temp files
Access HTTP API SQL File path
Scales to Billions of files Millions of rows One machine
Cost per GB Very low Higher Local disk
Example Profile photo (5MB) User record Config file

The golden rule

Store the file in object storage. Store the reference (key or URL) in the database.


3. Use Cases

Object storage is the right tool whenever you have large binary files that do not belong in a database:

Use case Example
User profile pictures Avatar uploaded when signing up
Documents CV uploaded to a job board
Invoices and reports Generated PDF sent to a customer
Backups Database dump stored off-server
Large media Video recordings, podcast audio

4. Key Concepts - Buckets, Objects, and Keys

These three concepts are the building blocks of every object storage system.

image.png

Bucket - the top-level container. Like a drive or a top-level folder. Every file belongs to exactly one bucket. Bucket names must be unique.

Object - one stored file. It has three parts: the raw bytes, a key, and metadata.

Key - the unique name of the object inside the bucket. It is just a string. Slashes make it look like a folder path but there are no real folders underneath. Use a UUID in the key to prevent two users overwriting each other's files: avatars/a3f2b1c4-photo.jpg.


5. Public vs Private Buckets

Public bucket - anyone with the URL can access the file directly in their browser. No login needed. Good for logos and public images. Risk: the file is permanently accessible to anyone who knows the URL.

Private bucket - direct URLs return 403 Forbidden. Your Spring Boot app checks if the user is authorised and generates a signed URL. The user uses that URL to download directly from storage. Good for user uploads, invoices, medical records - anything sensitive.


6. Upload and Download via API

Object storage is accessed through HTTP. The operations map directly to HTTP methods:

Operation HTTP What happens
Upload PUT Store a new file
Download GET Retrieve a file
Delete DELETE Remove a file
List GET (bucket) List all files

The S3 API — One Standard, Every Provider

When Amazon built S3 in 2006 they also defined an API standard for how clients talk to object storage — how to upload, download, list, and delete files. That standard became so widely adopted that today almost every object storage provider implements it, including Backblaze B2, Cloudflare R2, MinIO, and DigitalOcean Spaces.

This matters for you as a developer because it means:

image.png

In practice you never write raw HTTP PUT and GET requests yourself. You use the AWS SDK which handles authentication, request signing, retries, and error handling for you. The SDK is just a clean Java wrapper around those HTTP calls - but knowing that HTTP is underneath helps you understand what the SDK is actually doing.


7. Presigned URLs - Temporary Access to Private Files

A presigned URL is a time-limited URL that gives temporary access to a private file — without needing credentials. After the time expires, the URL stops working automatically.

image.png

The key insight: Spring Boot never touches the file bytes. It only handles authorisation and generates the signed URL. The client downloads directly from Backblaze B2 — your server uses no bandwidth for the file transfer itself.

The URL contains an expiry timestamp and a cryptographic signature. After 15 minutes the URL stops working — no action needed on your side, it expires automatically.

Why presigned URLs are better than alternatives:

Approach Problem
Make bucket public Anyone can access any file permanently
Proxy through Spring Boot Your server downloads and re-streams — wastes bandwidth and compute
Presigned URL Client downloads directly, URL expires automatically, server only does auth check

8. Integrating Object Storage from Spring Boot

Here is the integration overview first — what the Spring Boot app needs and how it connects:

image.png

You need four things to connect Spring Boot to Backblaze B2. Now let's look at each one:

Step 1 — pom.xml: Add the AWS SDK. Backblaze B2 is S3-compatible so the same SDK works.

Step 2 — application.yaml: Add your B2 credentials (endpoint, region, keys, bucket name).

Step 3 — B2Config.java: Creates the S3Client bean — same @Configuration + @Bean pattern as AppConfig.java.

Step 4 — FileService.java: Three methods — upload, get presigned URL, delete.

Now let's see how these fit together in a request:

image.png

What you will use - Backblaze B2

Backblaze B2 is free (no credit card), S3-compatible, and simple to set up. You just need an email to sign up.

For the full account setup steps see the Backblaze B2 Setup Guide document.

Once you have your account details you will have:


Step 1 — Add the AWS SDK dependency

Backblaze B2 is S3-compatible so you use the AWS SDK pointed at Backblaze. Add to pom.xml:

xml

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.0</version>
</dependency>