Skip to main content

Overview

The feathers generate hook command creates a new hook file with the appropriate structure for your chosen hook type. Hooks are middleware functions that can be registered before, after, or on errors of service methods.

Usage

feathers generate hook [options]
Or using the shorthand:
feathers g hook [options]

Options

--name
string
The name of the hook. Will be used for the file name and function name.
feathers generate hook --name log-request
The name will be converted to camelCase for the function name and kebab-case for the file name.
--type
string
The type of hook to generate.
feathers generate hook --type around
Choices:
  • around - Around hooks wrap service methods
  • regular - Before, After, or Error hooks

Interactive Prompts

Hook Name

Prompt: “What is the name of the hook?” The name will be transformed:
  • camelCase for function names (e.g., logRequest)
  • kebab-case for file names (e.g., log-request.ts)

Hook Type

Prompt: “What kind of hook is it?” Choices:
  • Around - Wrap service methods with custom logic before and after execution
  • Before, After or Error - Run at a specific point in the service call lifecycle

Hook Types Explained

Around Hooks

Around hooks wrap the service method execution and can:
  • Run code before the method executes
  • Run code after the method executes
  • Modify the context before it reaches the method
  • Modify the result after the method completes
  • Handle errors from the method
  • Skip method execution entirely
Use cases:
  • Logging and timing
  • Caching
  • Transaction management
  • Performance monitoring

Regular Hooks

Regular hooks run at specific points:
  • Before hooks - Run before the service method
  • After hooks - Run after successful service method execution
  • Error hooks - Run when an error occurs
Use cases:
  • Validation
  • Data transformation
  • Populating related data
  • Sending notifications
  • Error handling

Generated Files

For a hook named “log-request”:
src/
└── hooks/
    └── log-request.ts

Generated Code Examples

Around Hook (TypeScript)

import { HookContext, NextFunction } from '../declarations'

export const logRequest = async (context: HookContext, next: NextFunction) => {
  console.log(`Running method ${context.method} on ${context.path}`)
  
  // Call next() to continue to the next hook or service method
  await next()
  
  console.log(`Finished method ${context.method} on ${context.path}`)
}

Regular Hook (TypeScript)

import { HookContext } from '../declarations'

export const logRequest = async (context: HookContext) => {
  console.log(`Running method ${context.method} on ${context.path}`)
  return context
}

Hook Context

All hooks receive a context object with the following properties:
app
Application
The Feathers application instance
service
Service
The service this hook is running on
path
string
The service path (e.g., “messages”)
method
string
The service method name (e.g., “create”, “find”, “get”, “update”, “patch”, “remove”)
type
string
The hook type: “before”, “after”, or “error”
params
Params
Service call parameters, including query, user, authentication info
data
any
Data submitted by the client (create, update, patch methods only)
id
string | number
The resource ID (get, update, patch, remove methods only)
result
any
The service method result (after hooks only)
error
Error
The error object (error hooks only)

Using Generated Hooks

After generating a hook, import and register it in your service:

Around Hook Usage

import { logRequest } from '../../hooks/log-request'

export const message = (app: Application) => {
  app.use(messagePath, new MessageService(getOptions(app)))

  app.service(messagePath).hooks({
    around: {
      all: [logRequest],
      // Or specific methods:
      // find: [logRequest],
      // create: [logRequest]
    }
  })
}

Regular Hook Usage

import { logRequest } from '../../hooks/log-request'

export const message = (app: Application) => {
  app.use(messagePath, new MessageService(getOptions(app)))

  app.service(messagePath).hooks({
    before: {
      all: [logRequest],
      // Or specific methods:
      // find: [logRequest],
      // create: [logRequest]
    },
    after: {
      all: [logRequest]
    },
    error: {
      all: [logRequest]
    }
  })
}

Terminal Output Example

$ feathers generate hook
? What is the name of the hook? log-request
? What kind of hook is it? Around

Generating hook...
 Created src/hooks/log-request.ts

Hook 'logRequest' created successfully!

Common Hook Patterns

Validation Hook

import { BadRequest } from '@feathersjs/errors'
import { HookContext } from '../declarations'

export const validateMessage = async (context: HookContext) => {
  const { data } = context
  
  if (!data.text || data.text.trim() === '') {
    throw new BadRequest('Message text is required')
  }
  
  if (data.text.length > 400) {
    throw new BadRequest('Message text cannot exceed 400 characters')
  }
  
  return context
}

Populate Hook

import { HookContext } from '../declarations'

export const populateUser = async (context: HookContext) => {
  const { app, result } = context
  
  // Populate user for a single result
  if (result.userId) {
    result.user = await app.service('users').get(result.userId)
  }
  
  // Populate users for paginated results
  if (result.data) {
    result.data = await Promise.all(
      result.data.map(async (item: any) => {
        if (item.userId) {
          item.user = await app.service('users').get(item.userId)
        }
        return item
      })
    )
  }
  
  return context
}

Authentication Hook

import { Forbidden } from '@feathersjs/errors'
import { HookContext } from '../declarations'

export const checkPermission = async (context: HookContext) => {
  const { params, id } = context
  
  if (!params.user) {
    throw new Forbidden('You must be logged in')
  }
  
  // Check if user owns the resource
  if (id) {
    const resource = await context.service.get(id)
    if (resource.userId !== params.user._id) {
      throw new Forbidden('You do not have permission to access this resource')
    }
  }
  
  return context
}

Around Hook with Timing

import { HookContext, NextFunction } from '../declarations'

export const measurePerformance = async (context: HookContext, next: NextFunction) => {
  const startTime = Date.now()
  
  console.log(`Starting ${context.method} on ${context.path}`)
  
  await next()
  
  const duration = Date.now() - startTime
  console.log(`Completed ${context.method} on ${context.path} in ${duration}ms`)
}

Caching Hook

import { HookContext, NextFunction } from '../declarations'

const cache = new Map()

export const cacheResults = async (context: HookContext, next: NextFunction) => {
  const { method, id, path } = context
  
  // Only cache GET requests
  if (method !== 'get') {
    return next()
  }
  
  const cacheKey = `${path}:${id}`
  
  // Return cached result if available
  if (cache.has(cacheKey)) {
    context.result = cache.get(cacheKey)
    return
  }
  
  await next()
  
  // Cache the result
  cache.set(cacheKey, context.result)
}

Hook Registration Levels

Hooks can be registered at different levels:

Application-Level Hooks

Run for all services:
app.hooks({
  around: {
    all: [logRequest]
  }
})

Service-Level Hooks

Run only for a specific service:
app.service('messages').hooks({
  before: {
    all: [authenticate('jwt')],
    create: [validateMessage]
  }
})

Method-Specific Hooks

Run only for specific methods:
app.service('messages').hooks({
  before: {
    find: [logRequest],
    create: [validateMessage, setTimestamp]
  },
  after: {
    find: [populateUser],
    get: [populateUser]
  }
})

Next Steps

Service documentation

Learn more about Feathers services

Authentication

Add authentication to your application
Hooks execute in the order they are registered. Place validation hooks before data transformation hooks.
Always return the context (for regular hooks) or call next() (for around hooks) to continue the hook chain.

Build docs developers (and LLMs) love