content-disposition vs content-type vs http-errors vs mime vs mime-types vs type-is
HTTP Header and MIME Type Utilities for Node.js
content-dispositioncontent-typehttp-errorsmimemime-typestype-isSimilar Packages:

HTTP Header and MIME Type Utilities for Node.js

These packages provide focused utilities for working with HTTP headers, MIME types, and error responses in Node.js applications. content-disposition and content-type parse and format specific HTTP headers. http-errors creates standard HTTP error objects with appropriate status codes and messages. mime and mime-types handle MIME type lookups and extensions, while type-is checks request content types against expected values. Together, they form a foundational toolkit for building robust HTTP servers and middleware.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
content-disposition90,884,79323819.2 kB154 months agoMIT
content-type014310.5 kB63 years agoMIT
http-errors01,55519.1 kB164 months agoMIT
mime02,352161 kB16 months agoMIT
mime-types01,45422.9 kB204 months agoMIT
type-is022721.3 kB13a year agoMIT

HTTP Header and MIME Type Utilities: A Practical Guide for Node.js Developers

When building HTTP servers or middleware in Node.js, you'll frequently encounter tasks like parsing headers, validating content types, generating proper error responses, and mapping file extensions to MIME types. The six packages in this comparison (content-disposition, content-type, http-errors, mime, mime-types, and type-is) each solve specific problems in this space with minimal, focused APIs. Let's explore how they work together and when to use each one.

📥 Content-Disposition: Safe File Downloads

The content-disposition package handles the Content-Disposition header, which tells browsers how to handle responses — particularly for file downloads.

Why not DIY? Manually constructing this header is risky because filenames can contain characters that break header parsing or enable response splitting attacks.

// Using content-disposition
const contentDisposition = require('content-disposition');

// Safe filename handling with proper encoding
const header = contentDisposition('résumé.pdf');
// Returns: 'inline; filename="resume.pdf"; filename*=UTF-8\'\'r%C3%A9sum%C3%A9.pdf'

// For attachments (downloads)
const attachmentHeader = contentDisposition('report.xlsx', { type: 'attachment' });

Without this package, you'd need to implement RFC 6266 compliance yourself, including UTF-8 encoding for international filenames and proper escaping.

🏷️ Content-Type: Parsing Media Types Correctly

The content-type package parses and formats Content-Type headers according to RFC 7231.

Why not DIY? Content-Type headers can include parameters (like charset=utf-8) and have subtle parsing rules around case sensitivity and whitespace.

// Using content-type
const contentType = require('content-type');

// Parsing a header
const parsed = contentType.parse('text/html; charset=utf-8');
// Returns: { type: 'text/html', parameters: { charset: 'utf-8' } }

// Formatting back to a string
const formatted = contentType.format(parsed);
// Returns: 'text/html; charset=utf-8'

// Works with request objects too
const reqType = contentType.parse(req);

Manual parsing would require handling edge cases like quoted parameters, multiple parameters, and ensuring the main type is normalized to lowercase.

❌ HTTP-Errors: Standard Error Objects

The http-errors package creates HTTP error objects with proper status codes, messages, and properties.

Why not DIY? Creating consistent error objects that work well with frameworks like Express requires setting multiple properties correctly.

// Using http-errors
const createError = require('http-errors');

// Creating specific errors
const notFound = createError(404, 'User not found');
const badRequest = createError.BadRequest('Invalid email format');
const unauthorized = createError.Unauthorized();

// Errors have proper properties
console.log(notFound.status); // 404
console.log(notFound.expose); // true (safe to show to users)

Without this, you'd manually set statusCode, status, expose, and other properties that Express and other middleware expect.

📁 MIME vs MIME-Types: Two Approaches to Type Lookup

Both mime and mime-types handle MIME type lookups, but with different scopes.

MIME Package (Full-Featured)

// Using mime
const mime = require('mime');

// Extension to type
const type = mime.getType('file.txt'); // 'text/plain'

// Type to extension
const ext = mime.getExtension('text/html'); // 'html'

// Custom types
mime.define({ 'application/custom': ['custom'] });

MIME-Types Package (Lightweight)

// Using mime-types
const mime = require('mime-types');

// Extension to type only
const type = mime.lookup('file.txt'); // 'text/plain'

// No reverse lookup available
// mime.extension('text/html') doesn't exist

// Get charset for a type
const charset = mime.charset('text/html'); // 'UTF-8'

Choose mime if you need bidirectional lookups or custom type definitions. Choose mime-types if you only need extension-to-type mapping and want a smaller dependency.

🔍 Type-Is: Content Type Validation

The type-is package checks if a request's Content-Type matches expected values.

Why not DIY? Content-Type validation needs to handle wildcards, specific types, and arrays of acceptable types while ignoring parameters.

// Using type-is
const typeis = require('type-is');

// Check against single type
if (typeis(req, 'application/json')) {
  // Handle JSON
}

// Check against array of types
if (typeis(req, ['json', 'urlencoded'])) {
  // Handle form data or JSON
}

// Wildcard support
if (typeis(req, 'application/*')) {
  // Handle any application type
}

// Get the actual matching type
const match = typeis(req, ['json', 'html']);
// Returns 'json', 'html', or false

Manual checking would require parsing the Content-Type header first and then implementing matching logic for wildcards and aliases.

🧩 How They Work Together

These packages are designed to complement each other in typical server scenarios:

// Example: File download endpoint
const express = require('express');
const createError = require('http-errors');
const contentDisposition = require('content-disposition');
const mime = require('mime');

app.get('/download/:filename', (req, res, next) => {
  const { filename } = req.params;
  
  // Validate file exists (simplified)
  if (!fileExists(filename)) {
    return next(createError.NotFound('File not found'));
  }
  
  // Set proper Content-Type
  const contentType = mime.getType(filename) || 'application/octet-stream';
  res.setHeader('Content-Type', contentType);
  
  // Set safe Content-Disposition
  res.setHeader('Content-Disposition', contentDisposition(filename));
  
  // Send file
  res.sendFile(filename);
});
// Example: API endpoint with validation
const typeis = require('type-is');
const createError = require('http-errors');

app.post('/api/users', (req, res, next) => {
  // Validate content type
  if (!typeis(req, ['json'])) {
    return next(createError.UnsupportedMediaType('Only JSON accepted'));
  }
  
  // Process JSON body
  // ...
});

⚠️ Common Pitfalls to Avoid

Don't Mix MIME Packages Unnecessarily

If you're already using mime, there's no need to also install mime-types. The mime package includes everything mime-types provides plus additional functionality.

Always Use content-disposition for Downloads

Never construct Content-Disposition headers manually:

// ❌ Dangerous - vulnerable to response splitting
res.setHeader('Content-Disposition', `attachment; filename="${userFilename}"`);

// ✅ Safe - properly escaped and encoded
res.setHeader('Content-Disposition', contentDisposition(userFilename));

Use http-errors Consistently

Mixing manual error objects with http-errors can lead to inconsistent behavior in error-handling middleware:

// ❌ Inconsistent
if (!user) {
  const err = new Error('Not found');
  err.statusCode = 404;
  next(err);
}

// ✅ Consistent
if (!user) {
  next(createError.NotFound('User not found'));
}

📊 When to Use Which Package

ScenarioRecommended Package(s)
Serving file downloadscontent-disposition + mime
Parsing request Content-Typecontent-type + type-is
Creating API error responseshttp-errors
Static file servermime-types (lighter) or mime (full-featured)
Validating request body formattype-is
Generating Content-Type headersmime

💡 Final Recommendation

These packages follow the Unix philosophy of doing one thing well. Rather than building monolithic utilities, they provide composable, focused tools that handle the tricky details of HTTP standards correctly.

  • Use content-disposition whenever you're setting that header — the security benefits alone justify the dependency.
  • Use content-type for parsing/formatting Content-Type headers — it handles RFC compliance so you don't have to.
  • Use http-errors for all error creation — it ensures consistency across your application.
  • Choose between mime and mime-types based on whether you need bidirectional lookups.
  • Use type-is for content type validation — it's much more reliable than manual string matching.

By using these specialized packages, you avoid common security vulnerabilities, ensure standards compliance, and write more maintainable code that clearly expresses its intent.

How to Choose: content-disposition vs content-type vs http-errors vs mime vs mime-types vs type-is

  • content-disposition:

    Choose content-disposition when you need to safely generate or parse the Content-Disposition header for file downloads. It properly handles filename encoding for special characters and prevents response splitting attacks by escaping newlines. This is essential for any application serving user-uploaded files or generating downloadable content.

  • content-type:

    Choose content-type when you need to parse or format Content-Type headers according to RFC 7231. It correctly handles media types with parameters (like charset) and provides normalized access to type and subtype. Use this instead of manual string parsing to avoid common pitfalls with parameter parsing and case sensitivity.

  • http-errors:

    Choose http-errors when you need to create HTTP error objects that follow standard conventions. It provides named constructors for all HTTP status codes (like createError.NotFound()) and ensures errors have proper status codes, message properties, and expose settings. This is crucial for consistent error handling in Express.js applications and custom middleware.

  • mime:

    Choose mime when you need a comprehensive MIME type database with both type-to-extension and extension-to-type lookups. It includes a large built-in database and supports custom type definitions. Use this over mime-types if you need extension lookups or want a single package that handles both directions of MIME type resolution.

  • mime-types:

    Choose mime-types when you only need extension-to-MIME-type lookups and want a lighter dependency. It's essentially the lookup functionality extracted from the mime package but without extension-to-type support. This is ideal for static file servers that map file extensions to Content-Type headers without needing reverse lookups.

  • type-is:

    Choose type-is when you need to check if an incoming request's Content-Type matches expected values. It supports wildcards (like application/*), specific types, and arrays of acceptable types. This is commonly used in middleware to validate request bodies before processing, ensuring your handlers only receive appropriately formatted data.

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