Skip to main content
Services are the heart of every Feathers application. A service is an object or class instance that implements certain methods. Services provide a uniform, protocol-independent interface for reading and writing data.

Service Interface

A service can implement any combination of the following methods:
interface ServiceMethods<Result = any, Data = Partial<Result>, ServiceParams = Params> {
  find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>
  get(id: Id, params?: ServiceParams): Promise<Result>
  create(data: Data, params?: ServiceParams): Promise<Result>
  update(id: NullableId, data: Data, params?: ServiceParams): Promise<Result | Result[]>
  patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]>
  remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]>
  setup?(app: Application, path: string): Promise<void>
  teardown?(app: Application, path: string): Promise<void>
}

Standard Methods

find()

Retrieve a list of resources. Can return paginated or unpaginated results.
find(params?: ServiceParams & { paginate?: PaginationParams }): Promise<Result | Result[]>
params
Params
Service call parameters
params.query
Query
Query parameters for filtering, sorting, and pagination
params.paginate
PaginationParams
Pagination configuration. Set to false to disable pagination.
result
Result[] | Paginated<Result>
Array of results, or a paginated result object with total, limit, skip, and data properties
// Find all users
const users = await app.service('users').find()

// Find with query
const activeUsers = await app.service('users').find({
  query: {
    active: true,
    $limit: 10,
    $skip: 0
  }
})

// Paginated result
const result = await app.service('users').find({
  query: { $limit: 10 }
})
console.log(result.total) // Total number of records
console.log(result.data)  // Array of 10 users

get()

Retrieve a single resource by its unique identifier.
get(id: Id, params?: ServiceParams): Promise<Result>
id
Id
required
The unique identifier of the resource (number or string)
params
Params
Service call parameters
result
Result
The resource object
// Get user by ID
const user = await app.service('users').get(1)

// Get with additional params
const user = await app.service('users').get(1, {
  query: { $select: ['name', 'email'] }
})

create()

Create one or more new resources.
create(data: Data, params?: ServiceParams): Promise<Result>
create(data: Data[], params?: ServiceParams): Promise<Result[]>
data
Data | Data[]
required
The data for the new resource(s). Can be a single object or an array of objects.
params
Params
Service call parameters
result
Result | Result[]
The created resource(s)
// Create a single user
const user = await app.service('users').create({
  name: 'John Doe',
  email: '[email protected]'
})

// Create multiple users
const users = await app.service('users').create([
  { name: 'John Doe', email: '[email protected]' },
  { name: 'Jane Smith', email: '[email protected]' }
])

update()

Replace a resource or multiple resources. The update method completely replaces the resource(s).
update(id: Id, data: Data, params?: ServiceParams): Promise<Result>
update(id: null, data: Data, params?: ServiceParams): Promise<Result[]>
id
Id | null
required
The unique identifier of the resource. Use null to update multiple resources.
data
Data
required
The complete new data for the resource(s)
params
Params
Service call parameters
result
Result | Result[]
The updated resource(s)
// Update a single user (replaces entire object)
const user = await app.service('users').update(1, {
  name: 'John Updated',
  email: '[email protected]',
  active: true
})

// Update multiple users
const users = await app.service('users').update(null, 
  { active: false },
  { query: { verified: false } }
)

patch()

Merge updates into a resource or multiple resources. Unlike update, patch only modifies the provided fields.
patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>
patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>
id
Id | null
required
The unique identifier of the resource. Use null to patch multiple resources.
data
PatchData
required
Partial data to merge into the resource(s)
params
Params
Service call parameters
result
Result | Result[]
The patched resource(s)
// Patch a single user (only updates provided fields)
const user = await app.service('users').patch(1, {
  active: true
})

// Patch multiple users
const users = await app.service('users').patch(null, 
  { verified: true },
  { query: { email: { $like: '%@example.com' } } }
)

remove()

Remove a resource or multiple resources.
remove(id: Id, params?: ServiceParams): Promise<Result>
remove(id: null, params?: ServiceParams): Promise<Result[]>
id
Id | null
required
The unique identifier of the resource. Use null to remove multiple resources.
params
Params
Service call parameters
result
Result | Result[]
The removed resource(s)
// Remove a single user
const removedUser = await app.service('users').remove(1)

// Remove multiple users
const removedUsers = await app.service('users').remove(null, {
  query: { active: false }
})

Lifecycle Methods

setup()

Called when the application is started. Use this to initialize connections, load data, etc.
setup?(app: Application, path: string): Promise<void>
app
Application
required
The Feathers application instance
path
string
required
The path where this service is registered
class MyService {
  async setup(app, path) {
    console.log(`Setting up service at ${path}`)
    // Initialize database connection, load cache, etc.
  }
  
  async find(params) {
    return []
  }
}

teardown()

Called when the application is shut down. Use this to close connections, clean up resources, etc.
teardown?(app: Application, path: string): Promise<void>
app
Application
required
The Feathers application instance
path
string
required
The path where this service is registered
class MyService {
  async teardown(app, path) {
    console.log(`Tearing down service at ${path}`)
    // Close database connection, flush cache, etc.
  }
  
  async find(params) {
    return []
  }
}

Service Parameters

Params

The params object contains metadata about the service call:
interface Params<Q = Query> {
  query?: Q
  provider?: string
  route?: { [key: string]: any }
  headers?: { [key: string]: any }
  // ... custom properties
}
query
Query
Query parameters for filtering and pagination
provider
string
The transport that made the service call (e.g., 'rest', 'socketio', undefined for internal calls)
route
object
Route parameters from the URL path
headers
object
HTTP headers from the request
class UserService {
  async find(params) {
    const { query, provider, user } = params
    
    // Internal call (no provider)
    if (!provider) {
      // Return all users
    }
    
    // External call
    // Apply security restrictions
  }
}

Service Options

When registering a service, you can pass options:
interface ServiceOptions {
  events?: string[]
  methods?: string[]
  serviceEvents?: string[]
  routeParams?: { [key: string]: any }
}
events
string[]
Custom events that this service emits to clients (merged with default events)
methods
string[]
Service methods that should be available externally to clients
serviceEvents
string[]
Full list of events this service emits (replaces default events)
routeParams
object
Initial data to always add as route params to this service
app.use('/messages', messageService, {
  methods: ['find', 'get', 'create'],
  events: ['typing', 'delivered'],
  routeParams: {
    appId: 'my-app'
  }
})

Custom Service Methods

Services can have custom methods in addition to the standard CRUD methods:
class UserService {
  async find(params) {
    return []
  }
  
  async resetPassword(data, params) {
    const { email } = data
    // Send password reset email
    return { message: 'Password reset email sent' }
  }
}

app.use('/users', new UserService(), {
  methods: ['find', 'resetPassword']
})

// Call custom method
await app.service('users').resetPassword({ email: '[email protected]' })

Protected Method Names

The following method names are reserved and cannot be used as custom methods:
  • All methods from Object.prototype and EventEmitter.prototype
  • all, around, before, after, error
  • hooks, setup, teardown, publish

Example Service

import { Id, Params } from '@feathersjs/feathers'

interface User {
  id: Id
  name: string
  email: string
  active: boolean
}

class UserService {
  private users: User[] = []
  private currentId = 0
  
  async setup(app, path) {
    console.log(`UserService registered at ${path}`)
  }
  
  async find(params?: Params) {
    const { query = {} } = params || {}
    let result = this.users
    
    if (query.active !== undefined) {
      result = result.filter(u => u.active === query.active)
    }
    
    return result
  }
  
  async get(id: Id, params?: Params) {
    const user = this.users.find(u => u.id === id)
    if (!user) {
      throw new Error(`User ${id} not found`)
    }
    return user
  }
  
  async create(data: Partial<User>, params?: Params) {
    const user: User = {
      id: ++this.currentId,
      name: data.name!,
      email: data.email!,
      active: data.active ?? true
    }
    this.users.push(user)
    return user
  }
  
  async patch(id: Id, data: Partial<User>, params?: Params) {
    const user = await this.get(id)
    Object.assign(user, data)
    return user
  }
  
  async remove(id: Id, params?: Params) {
    const index = this.users.findIndex(u => u.id === id)
    if (index === -1) {
      throw new Error(`User ${id} not found`)
    }
    return this.users.splice(index, 1)[0]
  }
  
  async teardown(app, path) {
    console.log(`UserService at ${path} shutting down`)
  }
}

app.use('/users', new UserService())

Build docs developers (and LLMs) love