Plugin helper for Fastify that adds skip-override property, validates Fastify version requirements, and manages plugin metadata including names, dependencies, and decorators.
npx @tessl/cli install tessl/npm-fastify-plugin@5.0.0Fastify Plugin is a utility library that provides a standardized wrapper for creating Fastify plugins with proper encapsulation control, dependency management, and version compatibility validation. It automatically adds the skip-override property to break encapsulation when needed, validates minimum Fastify version requirements, and manages plugin metadata including names, dependencies, and decorators.
npm install fastify-pluginconst fp = require('fastify-plugin');For TypeScript/ESM:
import fp from 'fastify-plugin';
// or
import { fastifyPlugin } from 'fastify-plugin';const fp = require('fastify-plugin');
// Callback-based plugin
module.exports = fp(function (fastify, opts, done) {
// Plugin logic here
fastify.decorate('utility', () => 'helper function');
done();
});
// Async plugin
module.exports = fp(async function (fastify, opts) {
// Plugin logic here
fastify.decorate('utility', () => 'helper function');
});
// With metadata options
module.exports = fp(function (fastify, opts, done) {
// Plugin logic here
done();
}, {
name: 'my-plugin',
fastify: '5.x',
dependencies: ['other-plugin']
});The main fastifyPlugin function wraps a plugin function to add necessary metadata and control encapsulation behavior.
/**
* Wraps a plugin function with metadata and encapsulation control
* @param {Function} fn - The plugin function (FastifyPluginCallback or FastifyPluginAsync)
* @param {Object|string} [options={}] - Plugin metadata options or Fastify version string
* @returns {Function} The wrapped plugin function with added metadata
*/
function fastifyPlugin(fn, options);Alternative export patterns:
// Available as default export
const fp = require('fastify-plugin');
// Available as named export
const { fastifyPlugin } = require('fastify-plugin');
// Available as .default property
const fp = require('fastify-plugin').default;Configuration object for specifying plugin requirements and dependencies.
interface PluginMetadata {
/** Bare-minimum version of Fastify for your plugin (semver range) */
fastify?: string;
/** Plugin name for dependency validation and collision prevention */
name?: string;
/** Decorator dependencies for this plugin */
decorators?: {
fastify?: (string | symbol)[];
reply?: (string | symbol)[];
request?: (string | symbol)[];
};
/** The plugin dependencies by name */
dependencies?: string[];
/** Whether to maintain encapsulation (default: false) */
encapsulate?: boolean;
}Usage Examples:
// Version requirement only
fp(plugin, '5.x');
// Full metadata
fp(plugin, {
name: 'my-awesome-plugin',
fastify: '5.x',
decorators: {
fastify: ['utility', 'helper'],
reply: ['serialize'],
request: ['validate']
},
dependencies: ['fastify-cors', 'fastify-helmet'],
encapsulate: false
});
// Encapsulated plugin
fp(plugin, {
name: 'encapsulated-plugin',
encapsulate: true
});Strongly typed wrapper for TypeScript projects with full generic type support.
declare function fastifyPlugin<
Options extends FastifyPluginOptions = Record<never, never>,
RawServer extends RawServerBase = RawServerDefault,
TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault,
Logger extends FastifyBaseLogger = FastifyBaseLogger,
Fn extends FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> | FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> = FastifyPluginCallback<Options, RawServer, TypeProvider, Logger>
>(
fn: Fn extends unknown ? Fn extends (...args: any) => Promise<any> ? FastifyPluginAsync<Options, RawServer, TypeProvider, Logger> : FastifyPluginCallback<Options, RawServer, TypeProvider, Logger> : Fn,
options?: PluginMetadata | string
): Fn;TypeScript Usage:
import { FastifyPluginAsync, FastifyPluginCallback } from 'fastify';
import fp from 'fastify-plugin';
// Typed callback plugin
const callbackPlugin: FastifyPluginCallback = (fastify, options, done) => {
fastify.decorate('utility', () => 'helper');
done();
};
export default fp(callbackPlugin);
// Typed async plugin
const asyncPlugin: FastifyPluginAsync = async (fastify, options) => {
fastify.decorate('utility', () => 'helper');
};
export default fp(asyncPlugin);By default, fastify-plugin adds the skip-override symbol to break Fastify's encapsulation, making plugin decorators available in the parent context:
// Without fastify-plugin - decorators are encapsulated
fastify.register(function (fastify, opts, done) {
fastify.decorate('utility', () => 'helper');
done();
});
// fastify.utility is undefined here
// With fastify-plugin - decorators are available in parent scope
fastify.register(fp(function (fastify, opts, done) {
fastify.decorate('utility', () => 'helper');
done();
}));
// fastify.utility is available hereIf no name is provided, fastify-plugin automatically generates one from the function name or file path:
function myCustomPlugin(fastify, opts, done) {
done();
}
// Automatic name: "myCustomPlugin"
fp(myCustomPlugin);
// Anonymous functions get auto-generated names with counter
fp(function (fastify, opts, done) { done(); });
// Name: "anonymous-auto-0", "anonymous-auto-1", etc.The plugin validates Fastify version compatibility using semver ranges:
// Requires Fastify 5.x
fp(plugin, { fastify: '5.x' });
// Requires Fastify 4.x or 5.x
fp(plugin, { fastify: '>=4.0.0 <6.0.0' });
// Just version string
fp(plugin, '5.x');The plugin validates inputs and throws descriptive errors:
// TypeError: fastify-plugin expects a function, instead got a 'string'
fp('not a function');
// TypeError: The options object should be an object
fp(plugin, []);
// TypeError: fastify-plugin expects a version string, instead got 'number'
fp(plugin, { fastify: 123 });Fastify-plugin supports various module patterns for better compatibility:
// Adds .default property for ESM compatibility
const wrappedPlugin = fp(plugin);
// wrappedPlugin.default === wrappedPlugin
// Adds camelCase property for TypeScript named imports
fp(plugin, { name: 'my-awesome-plugin' });
// Creates plugin.myAwesomePlugin propertyPlugins can declare dependencies on other plugins and decorators:
fp(plugin, {
name: 'my-plugin',
dependencies: ['fastify-cors'], // Requires fastify-cors to be registered first
decorators: {
fastify: ['authenticate'], // Requires authenticate decorator on fastify instance
reply: ['serialize'], // Requires serialize decorator on reply
request: ['validate'] // Requires validate decorator on request
}
});Properly handles scoped npm package names in camelCase conversion:
// @myorg/my-plugin becomes myorgMyPlugin
fp(plugin, { name: '@myorg/my-plugin' });/**
* @deprecated Use PluginMetadata instead
*/
interface PluginOptions extends PluginMetadata {}The plugin adds several symbols and properties to wrapped functions:
// Internal symbols added by fastify-plugin
Symbol.for('skip-override') // Controls encapsulation
Symbol.for('fastify.display-name') // Plugin display name
Symbol.for('plugin-meta') // Complete plugin metadata