@fastify/compress

repository·main·Indexed 42 days ago

https://github.com/fastify/fastify-compress

A Fastify plugin providing response compression (zstd, br, gzip, deflate) and request decompression capabilities. Version 9.2.0 features include global and per-route configuration, a synchronous compression path for small payloads via syncThreshold, and support for various input types including Node.js streams, Web ReadableStreams, and Fetch API Responses.

Tokens
4.5K
Snippets
16
Records
19
Agent score
3%

What's inside fastify-compress

  1. Optimize compression with syncThreshold

    main

    The syncThreshold option controls when responses are compressed synchronously versus via a streaming path.

    • Synchronous Path: Used for payloads (Strings or Buffers) smaller than syncThreshold. This is faster for small responses as it avoids the overhead of a zlib stream and uses less memory. Synchronous compression also allows for an accurate Content-Length header.
    • Streaming Path: Used for larger payloads, streams, Web ReadableStreams, and Fetch Responses. This offloads work to libuv's threadpool to avoid blocking the event loop.

    Note for CPU-constrained environments: In containers with limited CPU quotas (e.g., Kubernetes cpu: 500m), Node.js may incorrectly report a high number of cores. In these cases, you should explicitly set a higher syncThreshold to favor synchronous compression.

    await fastify.register(
      import('@fastify/compress'),
      { syncThreshold: 65536 }
    )
  2. Decompress request payloads

    main

    The plugin automatically adds a preParsing hook to decompress incoming request payloads based on the content-encoding header. Supported encodings include zstd (Node.js 22.15+/23.8+), br, gzip, and deflate.

    Configuration

    • Global Decompression: Enabled by default. Disable it via { global: false } in the plugin registration.
    • Per Route Decompression: Use the decompress option in route configuration to force an encoding or provide custom decompressors.
    • Supported Encodings: Restrict allowed request encodings using the requestEncodings option.
    // Per-route decompression configuration
    fastify.get('/custom-route', {
      decompress: {
        forceRequestEncoding: 'gzip',
        zlib: {
          createBrotliDecompress: () => createYourCustomBrotliDecompress(),
          createGunzip: () => createYourCustomGunzip(),
          createInflate: () => createYourCustomInflate()
        }
      }
    }, (req, reply) => {
      // ...
    })
  3. How @fastify/compress works

    main

    The plugin provides two main functionalities: a compression utility added to the Fastify reply object and a global hook for decompressing request payloads.

    It supports the following encoding tokens, selected in this priority order based on the accept-encoding header:

    1. zstd (Requires Node.js 22.15+/23.8+)
    2. br (Brotli)
    3. gzip
    4. deflate
    5. * (Defaults to gzip)
    6. identity (No compression)

    Compression is applied based on the content-type. If no content type is specified, it defaults to application/json.

    Note: For large-scale production environments, it is recommended to use a proxy like Nginx to handle response compression instead of the application layer.

  4. Handle unsupported response encodings

    main

    Use the onUnsupportedEncoding(encoding, request, reply) option to define a custom error response when a client requests an encoding that the server does not support. The function can return a string | Buffer | Stream | Error payload.

    await fastify.register(
      import('@fastify/compress'),
      {
        onUnsupportedEncoding: (encoding, request, reply) => {
          reply.code(406)
          return 'We do not support the ' + encoding + ' encoding.'
        }
      }
    )
  5. Define custom content types for compression

    main

    By default, compression is determined by mime-db. You can extend this by providing a Regular Expression or a function to the customTypes option to include additional content types.

    // Using a Regex
    await fastify.register(
      import('@fastify/compress'),
      { customTypes: /x-protobuf$/ }
    )
    
    // Using a function
    await fastify.register(
      import('@fastify/compress'),
      { customTypes: contentType => contentType.endsWith('x-protobuf') }
    )
  6. Configure per-route compression options

    main

    You can override global compression settings for specific routes using the compress key in the route configuration. Setting compress: false on a route will explicitly disable compression for that route, even if global compression is active.

    // Only compress if the payload is above a certain size and use custom zlib settings
    fastify.get('/custom-route', {
      compress: {
        inflateIfDeflated: true,
        threshold: 128,
        zlib: {
          createBrotliCompress: () => createYourBrotliCompress(),
          createGzip: () => createYourGzip(),
          createDeflate: () => createYourDeflate()
        }
      }
    }, (req, reply) => {
      // ...
    })
  7. Handle request decompression errors

    main

    Customize the error response for unsupported or invalid request encodings using these options:

    • onUnsupportedRequestEncoding(request, encoding): Returns an error when the client sends an encoding not in your allowed list.
    • onInvalidRequestPayload(request, encoding, error): Returns an error when the payload cannot be successfully decompressed.
    await fastify.register(
      import('@fastify/compress'),
      {
        onUnsupportedRequestEncoding: (request, encoding) => {
          return { 
            statusCode: 415, 
            code: 'UNSUPPORTED', 
            error: 'Unsupported Media Type', 
            message: 'We do not support the ' + encoding + ' encoding.' 
          }
        }
      }
    )
  8. Configure global compression and decompression

    main

    By default, the global compression hook is enabled. You can control the behavior of the plugin during registration using the following flags:

    • global: Set to false to disable the global hook entirely.
    • globalCompression: Set to false to disable response compression while keeping decompression enabled.
    • globalDecompression: Set to false to disable request decompression while keeping compression enabled.

    Important: If you are using @fastify/static, you must register @fastify/compress (with the global hook enabled) before registering @fastify/static.

    // Disable the global hook entirely
    await fastify.register(
      import('@fastify/compress'),
      { global: false }
    )
    
    // Disable compression but keep decompression enabled
    await fastify.register(
      import('@fastify/compress'),
      { globalCompression: false }
    )
    
    // Disable decompression but keep compression enabled
    await fastify.register(
      import('@fastify/compress'),
      { globalDecompression: false }
    )
  9. Configure encoding priority and supported encodings

    main

    Control which compression algorithms are used and their priority by passing an array of tokens to the encodings option.

    // Only support gzip and deflate, with deflate preferred
    await fastify.register(
      import('@fastify/compress'),
      { encodings: ['deflate', 'gzip'] }
    )
    
    // Example with zstd support (Node.js 22.15+/23.8+)
    await fastify.register(
      import('@fastify/compress'),
      { encodings: ['zstd', 'br', 'gzip'] }
    )
  10. Tune Brotli and Zlib compression settings

    main

    Pass native Node.js zlib options to brotliOptions and zlibOptions to fine-tune compression quality and parameters.

    server.register(fastifyCompress, {
      brotliOptions: {
        params: {
          [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT,
          [zlib.constants.BROTLI_PARAM_QUALITY]: 4,
        },
      },
      zlibOptions: {
        level: 6,
      }
    });