skip to content

Reactive Multipart & File Upload

Reactive uploads arrive as a Flux of Parts backed by DataBuffers, so a large file can be streamed to storage instead of buffered in memory. The memory argument is exactly why interviewers ask about it.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

How do you receive an uploaded file in a Spring WebFlux controller?

level: juniorimportance: must knowfreq 70%

answer

  1. @RequestPart FilePart
  2. transferTo(Path) -> Mono<Void>
  3. FilePart extends Part
  4. multipart/form-data
  5. never blocking Files.copy

basics

~10 s

Bind the named multipart part with @RequestPart to a FilePart parameter. FilePart exposes filename(), headers(), and transferTo(path) to save the upload. Return a Mono/Flux so the handler stays non-blocking.

solid answer

~30 s

In WebFlux a multipart request is decoded into Part objects. To grab one uploaded file you use @RequestPart("file") FilePart file — FilePart extends Part and adds filename() and transferTo(Path). You typically call file.transferTo(path) which returns Mono<Void> and streams the bytes to disk without blocking. The handler returns a reactive type (Mono<Void>, Mono<ResponseEntity>) so nothing blocks. @RequestPart binds a single named part; for form-field text parts you'd get a FormFieldPart with value(). Content type must be multipart/form-data. Never call blocking IO (e.g. Files.copy on an InputStream) — use transferTo or DataBufferUtils so the upload stays fully reactive and backpressure-aware.

code

java · 11 lines
java
@RestController
class UploadController {

    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    Mono<ResponseEntity<String>> upload(@RequestPart("file") FilePart file) {
        Path target = Path.of("/tmp/uploads", file.filename());
        // transferTo streams DataBuffers to disk and releases them; non-blocking
        return file.transferTo(target)
                   .thenReturn(ResponseEntity.ok("saved " + file.filename()));
    }
}

go deeper

for a junior

Know @RequestPart FilePart and transferTo return a Mono.

for a middle

Distinguish FilePart vs FormFieldPart and know the org.springframework.http.codec.multipart package, not Servlet MultipartFile.

for a senior

Explain why transferTo is non-blocking and buffer-safe versus blocking IO.

for a principal

Frame the choice of binding type against streaming vs buffering and thread-model implications.

**Multipart in WebFlux.** When a browser or client posts `multipart/form-data`, the body is a sequence of *parts*, each with its own headers (name, filename, content-type) and a body. Spring WebFlux models each part with the interface `org.springframework.http.codec.multipart.Part`. Sub-interfaces: - `FilePart` — a part that is an uploaded file. Adds `String filename()` and `Mono<Void> transferTo(Path)` / `transferTo(File)`. - `FormFieldPart` — a simple text form field. Adds `String value()`. **Binding with @RequestPart.** `@RequestPart("file")` selects the part whose `name` equals `file` and binds it. Valid target types include: - `FilePart` / `Part` — the raw part. - `Mono<FilePart>` — deferred access. - A POJO — the part's content is decoded through the configured codecs (e.g. a JSON part into an object). **Saving the file.** The idiomatic, non-blocking way is: ```java return file.transferTo(Path.of("/uploads/" + file.filename())); ``` `transferTo` streams the part's `DataBuffer`s to the target and **releases** them for you, returning `Mono<Void>` that completes when the write finishes. Do **not** grab an InputStream and call blocking `Files.copy` — that blocks an event-loop thread and defeats the reactive model. **Gotchas for a junior:** - The request must be `multipart/form-data`; a plain body won't decode into parts. - The handler must return a reactive type; returning `void` and doing the work imperatively risks the response completing before the async write finishes. - `@RequestPart` is WebFlux/MVC shared, but the WebFlux `FilePart` lives in `org.springframework.http.codec.multipart`, not the Servlet `MultipartFile`. - `@RequestParam` is for query/form-field values, not files, in WebFlux. **When to use.** Single named file upload — `@RequestPart FilePart`. Multiple/unknown parts — `Flux<Part>` (sibling question). Fully streaming pass-through — `PartEvent` API.

  • What is the difference between FilePart and FormFieldPart?
    Both extend Part. FilePart represents an uploaded file and adds filename() plus transferTo(); FormFieldPart represents a plain text form field and adds value(). You get FormFieldPart for non-file inputs in the same multipart body.
  • Why prefer transferTo over reading an InputStream?
    transferTo streams the part's DataBuffers reactively to the target, returns a Mono<Void> that signals completion, and releases the buffers automatically. Reading an InputStream and using Files.copy blocks an event-loop thread, breaking the non-blocking contract.

saying these in an interview costs you the question

  • Using Servlet MultipartFile in a WebFlux handler
  • Calling blocking Files.copy on an InputStream from the part
  • Returning void and doing the save imperatively so the response races the write
  • Using @RequestParam to bind the file

context

open as a page

How do you stream an uploaded part's content as DataBuffers to storage without buffering the whole file in memory?

level: seniorimportance: must knowfreq 40%

basics

~10 s

Use part.content(), which is a Flux<DataBuffer> streaming the body in chunks. Write it with DataBufferUtils.write(content, path) or FilePart.transferTo(path). Both stream chunk-by-chunk with backpressure and release each buffer.

open as a page

How do you handle a multipart request with an unknown number of parts (e.g. multiple files) in WebFlux?

level: middleimportance: should knowfreq 45%

basics

~10 s

Bind the whole body as Flux<Part> (or Mono<MultiValueMap<String, Part>>). Iterate the flux, check each part's type (FilePart vs FormFieldPart) via instanceof, and process filename/value accordingly.

open as a page

Which HttpMessageReaders decode multipart in WebFlux, and how do MultipartHttpMessageReader, DefaultPartHttpMessageReader, and the PartEvent reader differ?

level: seniorimportance: should knowfreq 30%

basics

~10 s

DefaultPartHttpMessageReader parses the body into a streaming Flux<Part>. MultipartHttpMessageReader wraps it and collects parts into a Mono<MultiValueMap<String, Part>>. PartEventHttpMessageReader produces a fully streaming Flux<PartEvent> without buffering to disk.

open as a page

What memory, backpressure, and buffer-lifecycle pitfalls must you handle when consuming reactive multipart uploads, and how do you build a safe zero-buffer streaming pipeline?

level: principalimportance: should knowfreq 18%

basics

~10 s

Consume parts sequentially (concatMap), always release DataBuffers on every path including discard/cancel/error, set reader limits (maxInMemorySize/maxParts/maxDiskUsagePerPart), let backpressure throttle reads, and prefer PartEvent to relay uploads downstream without touching heap or disk.

open as a page