Back to HTTP Headers

Content-Disposition content response

Controls whether the browser displays the response inline or downloads it as a file, and sets the suggested filename.

What it does

Content-Disposition tells the browser (or any HTTP client) what to do with the response body — either display it in the browser window (inline) or download it as a file (attachment). When downloading, it also provides the suggested filename.

It has a dual life: in HTTP responses it controls download behavior; in multipart/form-data request bodies it labels each individual part.

Syntax

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="<filename>"
Content-Disposition: attachment; filename*=UTF-8''<encoded-filename>

Examples:

Content-Disposition: inline
Content-Disposition: attachment; filename="report.pdf"
Content-Disposition: attachment; filename*=UTF-8''%E8%AB%8B%E6%B1%82%E6%9B%B8.pdf
Content-Disposition: form-data; name="avatar"; filename="photo.jpg"

Directive reference

Directive Meaning
inline Display the content in the browser if possible. Default if header is absent.
attachment Download the content as a file. Browser won't try to render it.
filename="<name>" Suggested filename for the download. Browser may use a different name.
filename*=UTF-8''<encoded> RFC 5987 encoded filename. Supports non-ASCII characters. Takes precedence over filename.
form-data Used in multipart bodies to label a form field or file part.
name="<field>" In multipart, the form field name this part belongs to.

The filename vs filename* problem

The plain filename parameter only reliably handles ASCII. For filenames with non-ASCII characters (Chinese, Arabic, accented characters, emoji), you need filename* using RFC 5987 encoding:

filename*=UTF-8''<percent-encoded filename>

Best practice: send both for maximum compatibility:

Content-Disposition: attachment; filename="document.pdf"; filename*=UTF-8''%E6%96%87%E6%9B%B8.pdf

Clients that understand filename* use it; older clients fall back to filename.

How it interacts with other headers

Content-Type and Content-Disposition work together to control file handling. Content-Type tells the browser what the file is; Content-Disposition: attachment tells it to download regardless. A PDF served with Content-Type: application/pdf alone will open in the browser's PDF viewer. Adding Content-Disposition: attachment forces a download instead.

Without Content-Disposition, whether a browser opens or downloads a file depends entirely on whether it has a handler for that Content-Type. Adding Content-Disposition: inline explicitly doesn't change this behaviour — it's the default. Adding attachment always forces a download.

Security implications

Never trust the filename from user input. If your server dynamically sets the filename from user-supplied data, a malicious user could inject characters like ../ to attempt path traversal, or inject additional headers by embedding newlines. Always sanitize or escape the filename value.

attachment doesn't prevent viewing. It just changes the default browser action. Users can still open the downloaded file in any application. Don't rely on Content-Disposition as a security control for sensitive files — use proper authentication and authorization.

Content-Disposition can prevent certain XSS vectors. If a server hosts user-uploaded HTML files, serving them with Content-Disposition: attachment forces a download rather than rendering — preventing script execution in the browser context of your origin.

Real-world examples

Forcing a PDF download:

HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="invoice-March-2026.pdf"
Content-Length: 204800

Serving an image inline (browser renders it):

HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Disposition: inline

File upload (multipart body):

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----Boundary

------Boundary
Content-Disposition: form-data; name="description"

My avatar photo
------Boundary
Content-Disposition: form-data; name="avatar"; filename="me.jpg"
Content-Type: image/jpeg

<binary data>
------Boundary--

Unicode filename:

Content-Disposition: attachment; filename="file.pdf"; filename*=UTF-8''%E8%AB%8B%E6%B1%82%E6%9B%B8.pdf

FAQ

What happens if I omit Content-Disposition entirely?

The browser falls back to its default behaviour based on Content-Type. If it knows how to display the type (HTML, images, PDF in modern browsers), it renders it inline. If it doesn't recognize the type, it downloads it. This makes behaviour inconsistent across browsers — if you specifically want a download, always set Content-Disposition: attachment explicitly.

Can I set a filename for an inline response?

The filename parameter is really only meaningful for attachment. You can technically put it on inline, but browsers ignore it — there's no filename to set when you're displaying something in the viewport rather than saving it.

Does Content-Disposition work for all file types?

Yes — attachment forces a download regardless of the MIME type. Even a plain .txt file that the browser would normally display as text will be downloaded if you set Content-Disposition: attachment.

Is there a size limit on the filename?

The HTTP spec doesn't set a hard limit, but OS filesystem limits apply to what the browser actually saves. Most file systems cap at 255 bytes for the filename. Practical advice: keep filenames short, avoid special characters beyond hyphens and underscores, and use filename* encoding for anything non-ASCII.

Fun fact

Content-Disposition was originally defined for MIME email (RFC 2183, 1997) before being adapted for HTTP. The web's use of it to trigger file downloads wasn't formalised until RFC 6266 in 2011 — meaning for over a decade, browsers had to reverse-engineer behaviour from inconsistent server implementations and each other. The filename* encoding (RFC 5987) came even later, which is why non-ASCII filenames have historically been such a mess to get right.