How to set a Content-Disposition filename

By

Write a Content-Disposition header for a download or an inline file, including the UTF-8 filename form, and read a header back.

Free toolThis tutorial uses the Content-Disposition Builder. It runs in your browser, so open it in another tab and follow along.

The Content-Disposition header names a file for the browser. It also says whether to save the file or show it.

attachment asks for a download. inline asks the browser to show the file when it can, such as a PDF in the tab. The filename is a parameter on that same line.

You can build the line in the Content-Disposition builder. The rules are the ones Express uses for res.download(), from the content-disposition package. Send files using Express covers that method.

A plain name

Type invoice.pdf and leave the type on attachment. The tool writes:

Type: attachment
Filename: invoice.pdf
filename parameter: invoice.pdf
filename*: no

Content-Disposition: attachment; filename="invoice.pdf"

The quotes wrap the name even when there is no space. Copy that line onto the response, next to the Content-Type. The Content-Type parser is the other half of that pair, and the header list is the wider reference.

A space in the name

Switch the type to inline and type November report.pdf. The tool writes:

Type: inline
Filename: November report.pdf
filename parameter: November report.pdf
filename*: no

Content-Disposition: inline; filename="November report.pdf"

The space stays inside the quotes. You do not percent-encode it in the filename parameter.

A character outside Latin-1

The euro sign is not Latin-1. A quoted filename cannot hold it. The header then sends two parameters. filename replaces the euro sign with ?. filename* carries the real name as UTF-8, percent-encoded. RFC 8187 defines that second form.

Type price-list-€.pdf. The tool writes:

Type: attachment
Filename: price-list-€.pdf
filename parameter: price-list-?.pdf
filename*: yes

Content-Disposition: attachment; filename="price-list-?.pdf"; filename*=UTF-8''price-list-%E2%82%AC.pdf

A character is outside Latin-1. filename uses ? for it, and filename* carries the UTF-8 name.

Filename you type Header the tool writes
invoice.pdf attachment; filename="invoice.pdf"
November report.pdf inline; filename="November report.pdf"
price-list-€.pdf attachment; filename="price-list-?.pdf"; filename*=UTF-8''price-list-%E2%82%AC.pdf
reports/invoice.pdf attachment; filename="invoice.pdf"

When both parameters are present, a browser uses filename*. Paste the euro header into the read box on the tool, with or without the Content-Disposition: prefix. The decoded name is price-list-€.pdf. The ? copy is the fallback for an old client.

Type: attachment
Filename: price-list-€.pdf
Parameters: 1
filename = price-list-€.pdf

Content-Disposition: attachment; filename="price-list-?.pdf"; filename*=UTF-8''price-list-%E2%82%AC.pdf

filename* replaces the earlier filename value.

é is Latin-1, so café.pdf stays in the quoted parameter and the tool does not add filename*.

Type: attachment
Filename: café.pdf
filename parameter: café.pdf
filename*: no

Content-Disposition: attachment; filename="café.pdf"
Which filename parameter to sendA Latin-1 name uses the filename parameter. A character outside Latin-1 also sends filename star with the UTF-8 bytes.NoYesFilenameOutside Latin-1?filenamefilename andfilename*

A path is not a filename

reports/invoice.pdf becomes invoice.pdf. The summary is the same plain header as invoice.pdf, and the page adds a note.

The directory was dropped. A filename is not a path.

The header names the file. It does not pick a folder on the visitor’s disk.

A quote inside the name is escaped. say "hi".pdf is written as:

Type: attachment
Filename: say "hi".pdf
filename parameter: say "hi".pdf
filename*: no

Content-Disposition: attachment; filename="say \"hi\".pdf"

Read a header you already have

Paste a header into the second box, with or without the Content-Disposition: prefix. The page lists the type and the filename.

If filename is repeated, the first value is kept. Paste attachment; filename="a.pdf"; filename="b.pdf".

Type: attachment
Filename: a.pdf
Parameters: 1
filename = a.pdf

Content-Disposition: attachment; filename="a.pdf"; filename="b.pdf"

A repeated filename was ignored. The first one is kept.

If filename* is also there, it replaces that value. That is the euro header above.

An unclosed quote is an error, and the page says so instead of guessing the name. Paste attachment; filename="invoice.pdf and the page says: A quoted parameter value never closed.

Try the Content-Disposition Builder

Build or read a Content-Disposition header. A non-Latin-1 filename gets a filename* parameter. The name stays in the browser.

Open the Content-Disposition Builder →

  • Content-Type Parser: Parse a Content-Type header into a media type, charset, and boundary. Quoted parameters are unescaped. The header stays in the browser.
  • MIME Type Lookup: Extension to MIME type and back — 150+ entries with Content-Type examples, charset notes, and gotchas.
  • HTTP Response Headers Explainer: Paste response headers and get each one explained — plus warnings for missing security headers like HSTS and CSP.

More tool tutorials →

Want me to talk about your product? You can sponsor this site.