content-disposition vs content-type
HTTP Header Utilities for Node.js Applications
content-dispositioncontent-typeSimilar Packages:

HTTP Header Utilities for Node.js Applications

content-disposition and content-type are specialized, low-level Node.js packages designed to parse and format specific HTTP headers according to RFC standards. The content-disposition package handles the Content-Disposition header, which controls how browsers present responses (e.g., inline display vs. file download). The content-type package manages the Content-Type header, which specifies the media type of a resource (e.g., application/json, text/html). Both libraries provide robust, spec-compliant utilities for working with these headers in server-side JavaScript environments.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
content-disposition023819.2 kB154 months agoMIT
content-type014310.5 kB63 years agoMIT

Parsing and Formatting HTTP Headers: content-disposition vs content-type

Both content-disposition and content-type solve focused problems in HTTP communication: they handle the parsing and formatting of two critical but distinct headers. While they share similar design philosophies — small, zero-dependency, spec-compliant utilities — they operate on entirely different parts of the HTTP protocol. Let’s examine how they differ in purpose, API, and real-world usage.

📥 What Each Package Handles: Different Headers, Different Jobs

content-disposition works exclusively with the Content-Disposition header. This header tells browsers how to handle the response body — whether to display it inline (inline) or prompt a file download (attachment). It also carries filename information.

// content-disposition: Creating a download header
const contentDisposition = require('content-disposition');
const header = contentDisposition('report.pdf', { type: 'attachment' });
// Result: 'attachment; filename="report.pdf"'

content-type deals only with the Content-Type header. This header defines the media type of the resource (e.g., text/plain, application/json) and may include parameters like charset=utf-8.

// content-type: Parsing a Content-Type header
const contentType = require('content-type');
const parsed = contentType.parse('application/json; charset=utf-8');
// Result: { type: 'application/json', parameters: { charset: 'utf-8' } }

These packages never overlap in functionality — you’ll often use both in the same application, just for different tasks.

🔧 Core APIs: Formatting vs Parsing Emphasis

While both packages support parsing and formatting, their primary strengths differ based on typical usage patterns.

Generating Headers

content-disposition shines when generating safe, RFC-compliant Content-Disposition headers, especially with filenames containing spaces or non-ASCII characters:

// content-disposition handles tricky filenames
const header = contentDisposition('résumé.txt');
// Result: 'inline; filename="resume.txt"; filename*=UTF-8\'\'r%C3%A9sum%C3%A9.txt'

content-type focuses on parsing existing Content-Type headers reliably, but can also format them:

// content-type formatting
const formatted = contentType.format({
  type: 'text/html',
  parameters: { charset: 'utf-8' }
});
// Result: 'text/html; charset=utf-8'

Parsing Headers

content-disposition can parse headers too, though this is less common:

// content-disposition parsing
const parsed = contentDisposition.parse('attachment; filename="data.csv"');
// Result: { type: 'attachment', parameters: { filename: 'data.csv' } }

content-type excels at parsing, automatically normalizing and validating input:

// content-type strict parsing
try {
  const parsed = contentType.parse('application/json; charset=utf-8');
} catch (err) {
  // Throws if header is invalid
}

⚠️ Error Handling Philosophy

Both packages throw errors on malformed input during parsing, but their tolerance differs slightly.

content-disposition will throw if the header doesn’t conform to expected syntax:

// This throws
try {
  contentDisposition.parse('invalid header');
} catch (err) {
  // TypeError: invalid Content-Disposition
}

content-type is similarly strict but provides clearer error messages about what part of the header failed:

// This throws
try {
  contentType.parse('not-a-type');
} catch (err) {
  // TypeError: invalid media type
}

Neither package attempts to “fix” bad input — they enforce correctness by design.

🌐 Real-World Usage Scenarios

Serving Downloadable Files

When implementing a file download endpoint, you’ll use content-disposition to set the correct header:

// Express.js example
app.get('/download/:filename', (req, res) => {
  const header = contentDisposition(req.params.filename, { type: 'attachment' });
  res.set('Content-Disposition', header);
  // ... send file
});

You might also use content-type in the same handler to ensure the correct MIME type:

const mimeType = getMimeType(req.params.filename); // e.g., 'text/csv'
res.set('Content-Type', contentType.format({ type: mimeType }));

Validating API Requests

When building an API that expects JSON, use content-type to verify the request:

// Middleware to check Content-Type
function jsonOnly(req, res, next) {
  try {
    const parsed = contentType.parse(req.headers['content-type']);
    if (parsed.type !== 'application/json') {
      return res.status(400).send('JSON only');
    }
    next();
  } catch (err) {
    return res.status(400).send('Invalid Content-Type');
  }
}

You wouldn’t use content-disposition here — it’s irrelevant to request validation.

📦 When You Need Both Together

In file upload/download systems, you’ll often combine both:

// File download endpoint
app.get('/files/:id', async (req, res) => {
  const file = await getFile(req.params.id);
  
  // Set Content-Type
  res.set('Content-Type', contentType.format({ type: file.mimeType }));
  
  // Set Content-Disposition
  res.set('Content-Disposition', 
    contentDisposition(file.originalName, { type: 'attachment' })
  );
  
  res.send(file.data);
});

Each package handles its own header without interference.

🛑 Common Misconceptions

  • Myth: “I can use content-type to handle file downloads.”

    • Reality: Content-Type tells the browser what the file is, but Content-Disposition tells it what to do with it. Both are needed for proper file handling.
  • Myth: “These packages work in browsers.”

    • Reality: They’re designed for Node.js server environments where you control HTTP headers. Browsers don’t let you set arbitrary response headers.

💡 Key Takeaways

Aspectcontent-dispositioncontent-type
Header ManagedContent-DispositionContent-Type
Primary Use CaseFile download prompts, filename handlingMIME type parsing/formatting
Special StrengthSafe filename encoding for all browsersStrict RFC-compliant parsing
Typical DirectionMostly outgoing (response headers)Both incoming (request) and outgoing

🆚 Final Recommendation

Don’t think of these as competitors — they’re teammates. Use content-disposition whenever you’re serving files that should be downloaded or displayed inline with custom filenames. Use content-type whenever you need to inspect or set the media type of a resource. In most web applications that handle file I/O, you’ll end up using both, each doing its own job precisely and without overlap.

How to Choose: content-disposition vs content-type

  • content-disposition:

    Choose content-disposition when you need to generate or parse the Content-Disposition header for file downloads or attachment handling. It correctly formats filenames with proper encoding for special characters and supports both inline and attachment dispositions. This package is essential for any server logic that serves user-uploaded files or generates downloadable content where filename integrity matters across different browsers.

  • content-type:

    Choose content-type when you need to parse or format Content-Type headers accurately according to RFC 7231. It cleanly separates MIME types from parameters (like charset) and validates inputs against the specification. Use this package whenever your application must inspect request/response media types, set appropriate response headers, or implement content negotiation based on MIME types.

README for content-disposition

content-disposition

NPM Version NPM Downloads Node.js Version Build Status Test Coverage

Create and parse HTTP Content-Disposition header

Installation

$ npm install content-disposition

API

const contentDisposition = require('content-disposition')

contentDisposition(filename, options)

Create an attachment Content-Disposition header value using the given file name, if supplied. The filename is optional and if no file name is desired, but you want to specify options, set filename to undefined.

res.setHeader('Content-Disposition', contentDisposition('∫ maths.pdf'))

note HTTP headers are of the ISO-8859-1 character set. If you are writing this header through a means different from setHeader in Node.js, you'll want to specify the 'binary' encoding in Node.js.

Options

contentDisposition accepts these properties in the options object.

fallback

If the filename option is outside ISO-8859-1, then the file name is actually stored in a supplemental field for clients that support Unicode file names and a ISO-8859-1 version of the file name is automatically generated.

This specifies the ISO-8859-1 file name to override the automatic generation or disables the generation all together, defaults to true.

  • A string will specify the ISO-8859-1 file name to use in place of automatic generation.
  • false will disable including a ISO-8859-1 file name and only include the Unicode version (unless the file name is already ISO-8859-1).
  • true will enable automatic generation if the file name is outside ISO-8859-1.

If the filename option is ISO-8859-1 and this option is specified and has a different value, then the filename option is encoded in the extended field and this set as the fallback field, even though they are both ISO-8859-1.

type

Specifies the disposition type, defaults to "attachment". This can also be "inline", or any other value (all values except inline are treated like attachment, but can convey additional information if both parties agree to it). The type is normalized to lower-case.

contentDisposition.parse(string)

const disposition = contentDisposition.parse('attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt')

Parse a Content-Disposition header string. This automatically handles extended ("Unicode") parameters by decoding them and providing them under the standard parameter name. This will return an object with the following properties (examples are shown for the string 'attachment; filename="EURO rates.txt"; filename*=UTF-8\'\'%e2%82%ac%20rates.txt'):

  • type: The disposition type (always lower case). Example: 'attachment'

  • parameters: An object of the parameters in the disposition (name of parameter always lower case and extended versions replace non-extended versions). Example: {filename: "€ rates.txt"}

Examples

Send a file for download

const contentDisposition = require('content-disposition')
const destroy = require('destroy')
const fs = require('fs')
const http = require('http')
const onFinished = require('on-finished')

const filePath = '/path/to/public/plans.pdf'

http.createServer(function onRequest (req, res) {
  // set headers
  res.setHeader('Content-Type', 'application/pdf')
  res.setHeader('Content-Disposition', contentDisposition(filePath))

  // send file
  const stream = fs.createReadStream(filePath)
  stream.pipe(res)
  onFinished(res, function () {
    destroy(stream)
  })
})

Testing

$ npm test

References

License

MIT