Handle File Downloads
- Copy-Paste into Your Project
- Downloading a File from Disk
- Fetching Content from a Service
- When to Use Each Approach
- Beyond the Basics
This article shows how to serve files for download from a Vaadin application using DownloadHandler and the Anchor component. It covers generated content, files from disk, and service-backed downloads. For progress tracking, inline rendering, and advanced features, see the Downloads reference.
Copy-Paste into Your Project
A self-contained view that generates and serves a CSV file for download:
Source code
Java
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.streams.DownloadHandler;
import com.vaadin.flow.server.streams.DownloadResponse;
@Route("download-example")
public class DownloadExampleView extends VerticalLayout {
public DownloadExampleView() {
Anchor downloadLink = new Anchor( 1
DownloadHandler.fromInputStream(event -> { 2
try {
byte[] csv = generateCsv(); 3
return new DownloadResponse( 4
new ByteArrayInputStream(csv),
"report.csv",
"text/csv",
csv.length);
} catch (Exception e) {
return DownloadResponse.error(500); 5
}
}), "Download Report");
add(downloadLink);
}
private byte[] generateCsv() {
// Replace with your report generation logic
String csv = "Name,Email\nAlice,alice@example.com\n";
return csv.getBytes(StandardCharsets.UTF_8);
}
}-
Anchorrenders a regular HTML link. The browser handles the download natively — no JavaScript needed. -
DownloadHandler.fromInputStream()accepts a callback that runs when the user clicks the link. -
Generates the content. Replace this with your own logic.
-
DownloadResponsebundles theInputStream, filename, content type, and content length. -
Returns an error response if content generation fails.
|
Note
|
Memory usage
This example builds the entire file in memory as a byte[] before serving it. This is fine for small files and low concurrency. For large files or many concurrent users, have your service return an InputStream that streams content directly — see Fetching Content from a Service.
|
Downloading a File from Disk
When a file already exists on the server’s filesystem, use DownloadHandler.forFile():
Source code
Java
Anchor download = new Anchor(
DownloadHandler.forFile(
new File("/data/exports/report.pdf")),
"Download Report");The filename and content type are inferred from the File object.
Fetching Content from a Service
In a typical application, the download content comes from a Spring service — generating a report, reading from a database, or fetching from cloud storage. Inject the service through the constructor and have it return an InputStream so that content is streamed directly to the browser without buffering the entire file in server memory:
Source code
Java
@Route("report-download")
public class ReportDownloadView extends VerticalLayout {
public ReportDownloadView(ReportService reportService) {
Anchor downloadLink = new Anchor(
DownloadHandler.fromInputStream(event -> {
try {
return new DownloadResponse(
reportService.generateMonthlyReport(), 1
"monthly-report.pdf",
"application/pdf",
-1); 2
} catch (Exception e) {
return DownloadResponse.error(500);
}
}), "Download Monthly Report");
add(downloadLink);
}
}-
The service returns an
InputStream. The content is streamed directly to the client without loading it all into memory first. -
Pass
-1when the content length isn’t known in advance. The browser won’t show a progress percentage, but memory usage stays low regardless of file size.
When to Use Each Approach
-
forFile()— the file already exists on disk. Simplest option, handles content type and filename automatically. -
fromInputStream()— content is generated dynamically or comes from a database, external API, or cloud storage. This is the most common approach. -
Lambda with
DownloadEvent— you need full control over the response, such as setting custom headers, writing directly to the output stream, or updating the UI after the download completes.
Beyond the Basics
This article covers the fundamentals, but Vaadin’s download API offers more:
-
Progress tracking — show a progress bar during large downloads using the fluent
whenStart(),onProgress(), andwhenComplete()callbacks -
Inline rendering — display content in the browser instead of downloading it by calling
inline()on the handler -
Static resources — serve files from the classpath or servlet context with
forClassResource()andforServletResource() -
Custom headers — set cache control, content disposition, and other response headers using the
DownloadEventAPI
See the Downloads reference for details on these features.