packages/compression-middleware/README.md
Response compression middleware for Remix. It negotiates br, gzip, and deflate from Accept-Encoding and applies sensible defaults for when compression is useful.
Accept-Encodingnpm i remix
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
let router = createRouter({
middleware: [compression()],
})
The middleware will automatically compress responses for compressible MIME types when:
Accept-Encoding header with a supported encoding)Content-Length is present, by default)Accept-Ranges: bytes)Default: 1024 (only enforced if Content-Length is present)
Set the minimum response size in bytes to compress:
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
let router = createRouter({
middleware: [
compression({
threshold: 2048, // Only compress responses ≥2KB
}),
],
})
Default: ['br', 'gzip', 'deflate']
Customize which compression algorithms to support:
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
let router = createRouter({
middleware: [
compression({
encodings: ['br', 'gzip'], // Only use Brotli and Gzip
}),
],
})
The encodings option can also be a function that receives the response:
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
let router = createRouter({
middleware: [
compression({
encodings: (response) => {
// Use different encodings for server-sent events
let contentType = response.headers.get('Content-Type')
return contentType?.startsWith('text/event-stream;')
? ['gzip', 'deflate']
: ['br', 'gzip', 'deflate']
},
}),
],
})
Default: Uses isCompressibleMimeType() from @remix-run/mime
You can customize this behavior with the filterMediaType option:
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
import { isCompressibleMimeType } from 'remix/mime'
let router = createRouter({
middleware: [
compression({
filterMediaType(mediaType) {
// Add a custom media type to the default compressible list
return isCompressibleMimeType(mediaType) || mediaType === 'application/vnd.example+data'
},
}),
],
})
Default: Uses Node.js defaults for zlib and Brotli, with automatic flush handling for server-sent events.
You can pass options options to the underlying Node.js zlib and brotli compressors for fine-grained control:
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
import { zlib } from 'node:zlib'
let router = createRouter({
middleware: [
compression({
zlib: {
level: 6,
},
brotli: {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 4,
},
},
}),
],
})
Like encodings, both zlib and brotli options can also be functions that receive the response:
import zlib from 'node:zlib'
import { createRouter } from 'remix/fetch-router'
import { compression } from 'remix/compression-middleware'
let router = createRouter({
middleware: [
compression({
brotli: (response) => {
let contentType = response.headers.get('Content-Type')
return {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: contentType?.startsWith('text/html;') ? 4 : 11,
},
}
},
}),
],
})
@remix-run/fetch-router - Router for the web Fetch API@remix-run/mime - MIME type utilities@remix-run/response - Response helpersMIT