Automatic and manual response compression functionality with intelligent algorithm selection, content-type filtering, and configurable compression thresholds.
When global: true is set (default), all routes automatically compress responses based on client Accept-Encoding headers and configured criteria.
// Automatic compression is enabled via plugin registration
// No additional API calls needed - handled by onSend hooksCompression Criteria:
x-no-compression header present in requestUsage Examples:
const fastify = require('fastify')({ logger: true });
// Enable automatic compression globally
await fastify.register(require('@fastify/compress'), {
global: true,
threshold: 1024,
encodings: ['br', 'gzip', 'deflate']
});
// This route will automatically compress large responses
fastify.get('/api/data', async (request, reply) => {
// Large JSON response will be automatically compressed
return {
data: Array.from({ length: 1000 }, (_, i) => ({ id: i, value: `item-${i}` }))
};
});
// Prevent compression with header
fastify.get('/api/no-compress', async (request, reply) => {
// Client can prevent compression by sending x-no-compression header
return { message: 'This won\'t be compressed if x-no-compression header present' };
});Use the reply.compress() method for explicit control over response compression.
/**
* Manually compress a response payload
* @param payload - Data to compress and send
*/
interface FastifyReply {
compress(payload: CompressiblePayload): void;
}
type CompressiblePayload =
| Buffer
| NodeJS.TypedArray
| ArrayBuffer
| string
| Iterable<Buffer | string>
| AsyncIterable<Buffer | string>
| Stream;Usage Examples:
// Manual compression with different payload types
fastify.get('/api/manual', async (request, reply) => {
const data = { message: 'Hello World', timestamp: Date.now() };
// Compress and send JSON data
reply.compress(data);
});
// Manual compression with buffer
fastify.get('/api/buffer', async (request, reply) => {
const buffer = Buffer.from('Large text content'.repeat(100));
// Compress and send buffer
reply.compress(buffer);
});
// Manual compression with stream
fastify.get('/api/stream', async (request, reply) => {
const { Readable } = require('stream');
const stream = Readable.from(function* () {
for (let i = 0; i < 1000; i++) {
yield `data chunk ${i}\n`;
}
}());
// Compress and send stream
reply.compress(stream);
});The plugin automatically determines which responses should be compressed based on Content-Type headers.
Default Compressible Types Pattern:
/^text\/(?!event-stream)|(?:\+|\/)json(?:;|$)|(?:\+|\/)text(?:;|$)|(?:\+|\/)xml(?:;|$)|octet-stream(?:;|$)/uBuilt-in Compressible Types:
text/* (except text/event-stream)*/*+json, */json*/*+text, */text*/*+xml, */xmlapplication/octet-streamUsage Examples:
// Route with different content types
fastify.get('/api/json', async (request, reply) => {
reply.type('application/json');
return { data: 'compressible JSON' }; // Will be compressed
});
fastify.get('/api/text', async (request, reply) => {
reply.type('text/plain');
return 'This is compressible text'; // Will be compressed
});
fastify.get('/api/binary', async (request, reply) => {
reply.type('application/pdf');
return pdfBuffer; // Won't be compressed (not in default pattern)
});
// Override content-type detection per route
fastify.get('/api/custom', {
compress: {
customTypes: (contentType) => contentType.startsWith('application/pdf')
}
}, async (request, reply) => {
reply.type('application/pdf');
return pdfBuffer; // Will be compressed due to custom type function
});The plugin selects compression algorithms based on client Accept-Encoding headers and configured preferences.
Default Algorithm Priority:
zstd (Node.js 22.15+/23.8+)br (Brotli)gzipdeflateidentity (no compression)Usage Examples:
// Configure algorithm preferences
await fastify.register(require('@fastify/compress'), {
encodings: ['br', 'gzip', 'deflate'] // Skip zstd, prefer Brotli
});
// Client Accept-Encoding examples:
// "gzip, deflate, br" -> selects 'br' (highest priority available)
// "gzip, deflate" -> selects 'gzip' (deflate has lower priority)
// "deflate" -> selects 'deflate' (only option available)
// "*" -> selects 'gzip' (default for wildcard)
// "identity" -> no compressionConfigure minimum payload sizes to trigger compression, avoiding overhead for small responses.
/**
* Compression threshold configuration
*/
interface ThresholdOptions {
/** Minimum payload size in bytes to trigger compression (default: 1024) */
threshold?: number;
}Usage Examples:
// Global threshold
await fastify.register(require('@fastify/compress'), {
threshold: 2048 // Only compress responses >= 2KB
});
// Route-specific threshold
fastify.get('/api/data', {
compress: {
threshold: 512 // Compress responses >= 512 bytes for this route
}
}, async (request, reply) => {
return largeDataObject;
});
// Small responses won't be compressed
fastify.get('/api/ping', async (request, reply) => {
return { status: 'ok' }; // Too small, won't be compressed
});Handle content that's already compressed, with optional inflation for non-supporting clients.
/**
* Pre-compressed content handling options
*/
interface PreCompressedOptions {
/** Inflate pre-compressed content for clients that don't support compression */
inflateIfDeflated?: boolean;
}Usage Examples:
// Enable inflation for pre-compressed content
await fastify.register(require('@fastify/compress'), {
inflateIfDeflated: true
});
// Route serving pre-compressed content
fastify.get('/api/precompressed', async (request, reply) => {
// Content is already gzip compressed
const precompressedBuffer = getPrecompressedData();
// Plugin detects compression and handles appropriately:
// - If client supports gzip: sends as-is with Content-Encoding: gzip
// - If client doesn't support gzip: inflates and sends uncompressed
return precompressedBuffer;
});The plugin automatically manages compression-related HTTP headers.
Automatic Header Handling:
Content-Encoding header to selected algorithmVary: accept-encoding headerContent-Length header (configurable)/**
* Header management options
*/
interface HeaderOptions {
/** Remove Content-Length header when compressing (default: true) */
removeContentLengthHeader?: boolean;
}Usage Examples:
// Keep Content-Length header (not recommended)
await fastify.register(require('@fastify/compress'), {
removeContentLengthHeader: false
});
// Headers automatically set by plugin:
fastify.get('/api/data', async (request, reply) => {
return largeObject;
// Response headers will include:
// Content-Encoding: gzip (or br, deflate, etc.)
// Vary: accept-encoding
// Content-Length header removed (default behavior)
});Handle both buffer payloads and streaming responses with appropriate compression.
Usage Examples:
const { Readable } = require('stream');
const fs = require('fs');
// Compress streaming file response
fastify.get('/api/download', async (request, reply) => {
const fileStream = fs.createReadStream('large-file.json');
// Plugin automatically detects stream and applies streaming compression
reply.compress(fileStream);
});
// Compress generated streaming content
fastify.get('/api/generated', async (request, reply) => {
const dataStream = Readable.from(async function* () {
for (let i = 0; i < 10000; i++) {
yield JSON.stringify({ id: i, data: `item-${i}` }) + '\n';
// Allow other operations
if (i % 100 === 0) await new Promise(resolve => setImmediate(resolve));
}
}());
reply.type('application/x-ndjson');
reply.compress(dataStream);
});Override global compression settings on a per-route basis.
/**
* Route compression configuration
*/
interface RouteOptions {
/** Route-specific compression options, or false to disable */
compress?: RouteCompressOptions | false;
}
type RouteCompressOptions = Pick<FastifyCompressOptions,
| 'brotliOptions'
| 'customTypes'
| 'encodings'
| 'inflateIfDeflated'
| 'onUnsupportedEncoding'
| 'removeContentLengthHeader'
| 'threshold'
| 'zlib'
| 'zlibOptions'
>;Usage Examples:
// Route with custom compression settings
fastify.get('/api/high-compression', {
compress: {
encodings: ['br'], // Only use Brotli
threshold: 100, // Compress even small responses
brotliOptions: {
params: {
[require('zlib').constants.BROTLI_PARAM_QUALITY]: 11 // Maximum compression
}
}
}
}, async (request, reply) => {
return await getDataForHighCompression();
});
// Route with compression disabled
fastify.get('/api/no-compress', {
compress: false
}, async (request, reply) => {
return { message: 'Never compressed' };
});
// Route with custom content type matching
fastify.get('/api/custom-types', {
compress: {
customTypes: /^application\/(pdf|zip)/ // Compress PDF and ZIP files
}
}, async (request, reply) => {
reply.type('application/pdf');
return pdfBuffer;
});