Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ await fastify.register(
{ global: false }
)
```

If only compression or decompression is required, set the `globalCompression` or `globalDecompression` config flags to `false` respectively (both are `true` by default).

```js
await fastify.register(
import('@fastify/compress'),
// only decompress compressed incoming requests
{ globalCompression: false }
)
Comment on lines +65 to +67
Copy link

Copilot AI Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The example shows only disabling compression but the comment mentions 'only decompress'. Consider showing both options or clarifying that globalDecompression defaults to true.

Suggested change
// only decompress compressed incoming requests
{ globalCompression: false }
)
// Disable compression but keep decompression enabled (default behavior for globalDecompression is true)
{ globalCompression: false }
)
// Disable decompression but keep compression enabled
await fastify.register(
import('@fastify/compress'),
{ globalDecompression: false }
)

Copilot uses AI. Check for mistakes.
```

Fastify encapsulation can be used to set global compression but run it only in a subset of routes by wrapping them inside a plugin.

> ℹ️ Note: If using `@fastify/compress` plugin together with `@fastify/static` plugin, `@fastify/compress` must be registered (with *global hook*) **before** registering `@fastify/static`.
Expand Down
8 changes: 6 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ function processCompressParams (opts) {
}

const params = {
global: (typeof opts.global === 'boolean') ? opts.global : true
global: (typeof opts.globalCompression === 'boolean')
? opts.globalCompression
: (typeof opts.global === 'boolean') ? opts.global : true
}

params.removeContentLengthHeader = typeof opts.removeContentLengthHeader === 'boolean' ? opts.removeContentLengthHeader : true
Expand Down Expand Up @@ -173,7 +175,9 @@ function processDecompressParams (opts) {
const customZlib = opts.zlib || zlib

const params = {
global: (typeof opts.global === 'boolean') ? opts.global : true,
global: (typeof opts.globalDecompression === 'boolean')
? opts.globalDecompression
: (typeof opts.global === 'boolean') ? opts.global : true,
onUnsupportedRequestEncoding: opts.onUnsupportedRequestEncoding,
onInvalidRequestPayload: opts.onInvalidRequestPayload,
decompressStream: {
Expand Down
149 changes: 149 additions & 0 deletions test/global-compress.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3298,3 +3298,152 @@ for (const contentType of notByDefaultSupportedContentTypes) {
t.assert.equal(response.rawPayload.toString('utf-8'), file)
})
}

test('It should support separate globalCompression and globalDecompression settings', async (t) => {
t.plan(3)

// Test case: disable compression but enable decompression globally
const fastify = Fastify()
await fastify.register(compressPlugin, {
globalCompression: false,
globalDecompression: true
})

const testData = { message: 'test data for decompression only' }

fastify.get('/', (request, reply) => {
reply.send(testData)
})

// Test that compression is disabled
const getResponse = await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip, deflate, br'
}
})

t.assert.equal(getResponse.statusCode, 200)
// No compression should happen since globalCompression is false
t.assert.equal(getResponse.headers['content-encoding'], undefined)
t.assert.deepEqual(getResponse.json(), testData)
})

test('It should enable decompression when globalDecompression is true', async (t) => {
t.plan(2)

// Test case: enable decompression globally
const fastify = Fastify()
await fastify.register(compressPlugin, {
globalCompression: false,
globalDecompression: true
})

// Create a compressed request payload to test decompression
const compressedPayload = zlib.gzipSync(JSON.stringify({ input: 'compressed data' }))

fastify.post('/', (request, reply) => {
// This should be decompressed automatically
reply.send({ received: request.body })
})

// Test that decompression is enabled
const postResponse = await fastify.inject({
url: '/',
method: 'POST',
headers: {
'content-encoding': 'gzip',
'content-type': 'application/json'
},
payload: compressedPayload
})

t.assert.equal(postResponse.statusCode, 200)
// Decompression should work since globalDecompression is true
t.assert.deepEqual(postResponse.json(), { received: { input: 'compressed data' } })
})

test('It should fall back to global option when specific options are not provided', async (t) => {
t.plan(2)

// Test that global: false affects both compression and decompression
const fastify = Fastify()
await fastify.register(compressPlugin, {
global: false
})

const testData = { message: 'test data' }

fastify.get('/', (request, reply) => {
reply.send(testData)
})

const response = await fastify.inject({
url: '/',
method: 'GET',
headers: {
'accept-encoding': 'gzip, deflate, br'
}
})

t.assert.equal(response.statusCode, 200)
// No compression should happen since global is false
t.assert.equal(response.headers['content-encoding'], undefined)
})

test('It should demonstrate globalCompression overrides global setting', async (t) => {
t.plan(2)

// Test that globalCompression: true overrides global: false
const fastify = Fastify()
await fastify.register(compressPlugin, {
global: false,
globalCompression: true,
threshold: 0
})

fastify.get('/', (request, reply) => {
reply.send({ message: 'globalCompression overrides global' })
})

const response = await fastify.inject({
url: '/',
method: 'GET',
headers: { 'accept-encoding': 'gzip' }
})

t.assert.equal(response.statusCode, 200)
t.assert.equal(response.headers['content-encoding'], 'gzip') // Compression enabled despite global: false
})

test('It should demonstrate globalDecompression controls decompression independently', async (t) => {
t.plan(2)

// Test globalDecompression: false disables decompression even with global: true
const fastify = Fastify()
await fastify.register(compressPlugin, {
global: true,
globalDecompression: false
})

const compressedPayload = zlib.gzipSync(JSON.stringify({ test: 'decompression' }))

fastify.post('/', (request, reply) => {
reply.send({ received: request.body })
})

const response = await fastify.inject({
url: '/',
method: 'POST',
headers: {
'content-encoding': 'gzip',
'content-type': 'application/json'
},
payload: compressedPayload
})

// Should get 400 error since decompression is disabled and compressed data can't be parsed
t.assert.equal(response.statusCode, 400)
t.assert.ok(response.body.includes('Content-Length') || response.body.includes('Bad Request'))
})
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ declare namespace fastifyCompress {
encodings?: EncodingToken[];
forceRequestEncoding?: EncodingToken;
global?: boolean;
globalDecompression?: boolean;
globalCompression?: boolean;
inflateIfDeflated?: boolean;
onInvalidRequestPayload?: (encoding: string, request: FastifyRequest, error: Error) => Error | undefined | null;
onUnsupportedEncoding?: (encoding: string, request: FastifyRequest, reply: FastifyReply) => string | Buffer | Stream;
Expand Down