Spring Boot
Multipart File Upload
Java
REST API
File Handling

Multipart File upload Spring Boot

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Multipart upload in Spring Boot is usually straightforward: accept a MultipartFile, validate it, and store it somewhere safe. The part that deserves care is not the controller signature itself, but file-size limits, filename sanitization, and deciding whether the file belongs on local disk, object storage, or a database-backed workflow.

Basic Upload Endpoint

Spring Boot already supports multipart requests through Spring MVC. A minimal controller can accept both the file and other form fields in the same request.

java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4import java.nio.file.Paths;
5
6import org.springframework.http.ResponseEntity;
7import org.springframework.web.bind.annotation.PostMapping;
8import org.springframework.web.bind.annotation.RequestParam;
9import org.springframework.web.bind.annotation.RestController;
10import org.springframework.web.multipart.MultipartFile;
11
12@RestController
13public class FileUploadController {
14    private final Path uploadDir = Paths.get("uploads");
15
16    @PostMapping("/files/upload")
17    public ResponseEntity<String> upload(
18            @RequestParam("file") MultipartFile file,
19            @RequestParam("description") String description) throws IOException {
20
21        Files.createDirectories(uploadDir);
22        Path target = uploadDir.resolve(file.getOriginalFilename()).normalize();
23        file.transferTo(target);
24
25        return ResponseEntity.ok("uploaded: " + description);
26    }
27}

This shows the shape of the endpoint, but it is not yet production-ready.

Configure Multipart Limits Explicitly

Do not rely on defaults for file size. Set request limits in configuration so oversized uploads fail predictably.

properties
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

These properties prevent a single request from consuming more space than the application expects.

Sanitize the Filename

The original filename comes from the client and should not be trusted blindly. A user can submit names containing path traversal attempts or platform-specific characters.

A safer pattern is to normalize the path and reject files that escape the upload directory.

java
1String original = file.getOriginalFilename();
2Path target = uploadDir.resolve(original).normalize();
3
4if (!target.startsWith(uploadDir)) {
5    throw new IllegalArgumentException("invalid filename");
6}

In many systems it is even better to generate your own server-side filename and keep the client name only as metadata.

Validate Type and Empty Uploads

A file upload endpoint should usually reject empty files and validate the content type or extension according to business rules.

java
1if (file.isEmpty()) {
2    throw new IllegalArgumentException("empty file");
3}
4
5if (!"image/png".equals(file.getContentType())) {
6    throw new IllegalArgumentException("only PNG files are allowed");
7}

Do not treat MIME type checks as perfect security, but they are still a useful first filter.

Separate Storage From the Controller

As the feature grows, move the actual storage logic into a service. That keeps the controller small and makes the storage backend replaceable.

java
1import java.io.IOException;
2import java.nio.file.Files;
3import java.nio.file.Path;
4
5import org.springframework.stereotype.Service;
6import org.springframework.web.multipart.MultipartFile;
7
8@Service
9public class FileStorageService {
10    private final Path uploadDir = Path.of("uploads");
11
12    public Path store(MultipartFile file) throws IOException {
13        Files.createDirectories(uploadDir);
14        Path target = uploadDir.resolve(file.getOriginalFilename()).normalize();
15        if (!target.startsWith(uploadDir)) {
16            throw new IllegalArgumentException("invalid filename");
17        }
18        file.transferTo(target);
19        return target;
20    }
21}

That structure makes it easier to switch from local disk to S3 or another storage system later.

Think About Where the File Should Live

Local disk is fine for demos and small internal tools, but many real applications store uploads in object storage and keep only metadata in the database. That design matters because web servers may scale horizontally, containers may be ephemeral, and local filesystem assumptions often break first in production.

Choose the storage target deliberately instead of assuming the controller’s machine is the long-term home of the file.

Common Pitfalls

The most common mistake is trusting getOriginalFilename() and writing it directly to disk without validation.

Another issue is keeping all upload logic in the controller, which becomes hard to test and hard to evolve.

A third problem is forgetting to set multipart size limits, which turns large uploads into operational surprises.

Summary

  • Spring Boot accepts multipart uploads naturally through MultipartFile.
  • Set explicit multipart size limits in configuration.
  • Sanitize or replace client-provided filenames before storing files.
  • Validate empty uploads and allowed content types.
  • Move storage behavior into a service so the controller stays small and safe.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.