This guide explains the new features and changes to migrate to the Feathers v4 (Crow) release.


Instead of separate versioning for each module, all modules in the @feathersjs namespace have been updated to use the same version number. This means that the current release (Crow) will be Feathers v4. You can use e.g. a tool like npm-check-update to upgrade all dependencies to the latest version:

npm install npm-check-updates -g
ncu -u -t # -t includes latest prereleases as well


The @feathersjs/authentication-* modules have been completely rewritten to include more secure defaults, be easier to customize, framework independent and no longer rely on PassportJS. It comes with:

  • Protocol independent, fully customizable authentication strategies
  • An extensible authentication service that can register strategies and create authentication tokens (JWT by default but pluggable for anything else)
  • Better oAuth authentication with 180+ providers supported out of the box without any additional configuration (other than adding the application key and secret)
  • Built-in oAuth account linking and cross-domain oAuth authentication

To upgrade, replace the existing authentication configuration (usually src/authentication.js) with the following:

const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication');
const { LocalStrategy } = require('@feathersjs/authentication-local');
const { express: oauth } = require('@feathersjs/authentication-oauth');

module.exports = function (app) {
  const authentication = new AuthenticationService(app);

  authentication.register('jwt', new JWTStrategy());
  authentication.register('local', new LocalStrategy());

  app.use('/authentication', authentication);

Important: The @feathersjs/authentication-jwt is now deprecated since the JWT strategy is now directly included in @feathersjs/authentication.

This will register local, jwt and oAuth authentication strategies using the standard authentication service on the /authentication path. oAuth will only be active if provider information is added to the configuration. The authentication configuration (usually in config/default.json) should be updated as follows:

"authentication": {
  "entity": "user",
  "service": "users",
  "secret": "<your secret>",
  "authStrategies": [ "jwt", "local" ],
  "jwtOptions": {
    "header": { "typ": "access" },
    "audience": "https://yourdomain.com",
    "issuer": "feathers",
    "algorithm": "HS256",
    "expiresIn": "1d"
  "local": {
    "usernameField": "email",
    "passwordField": "password"

Important things to note:

  • Because of extensive changes and security improvements, you should change your JWT secret so that all users will be prompted to log in again.
  • The jwt options have been moved to jwtOptions. It takes all jsonwebtoken options. The subject option should be removed when using the standard setup.
  • authStrategies are the strategies that are allowed on this authentication endpoint

Important: The hashPassword hook now explicitly requires the name of the field to hash instead of using a default (change any hashPassword() to e.g. hashPassword('password')).

Feathers core

Services at the root level

Any Feathers application now allows to register a service at the root level with a name of /:

app.use('/', myService);

It will be available via app.service('/') through the client and directly at http://feathers-server.com/ via REST.

Skip event emitting

Service events can no be skipped by setting context.event to null.

context => {
  // Skip sending event
  context.event = null;

Typescript definitions included

All @feathersjs modules now come with up-to-date TypeScript definitions. Any definitions using @types/feathersjs__* should be removed from your project.

Deprecated (context, next) and SKIP functionality

In preparation to support Koa style hooks (see feathersjs/feathers#932) returning SKIP and calling the deprecated next function in hooks has been removed. Returning SKIP in hooks was causing issues because

  • It is not easily possible to see if a hook makes its following hooks skip. This made hook chains very hard to debug.
  • Returning SKIP also causes problems with Feathers internals like the event system

The use-cases for feathers.SKIP can now be explicitly handled by

Database adapters

The latest versions of the Feathers database adapters include some important security and usability updates by requiring to explicitly enable certain functionality that was previously available by default.

Querying by id

All database adapters now support additional query parameters for get, remove, update and patch. If the record does not match that query, even if the id is valid, a NotFound error will be thrown. This is very useful for the common case of e.g. restricting requests to the users company the same way as you already would in a find method:

// Will throw `NotFound` if `companyId` does not match
// Even if the `id` is available
app.service('/messages').get('<message id>', {
  query: { companyId: '<my company>' }

Hook-less service methods

The database adapters now support calling their service methods without any hooks by adding a _ in front of the method name as _find, _get, _create, _patch, _update and _remove. This can be useful if you need the raw data from the service and don't want to trigger any of its hooks.

// Call `get` without running any hooks
const message = await app.service('/messages')._get('<message id>');

Note: These methods are only available internally on the server, not on the client side and only for the Feathers database adapters. They do not send any events.

Multi updates

Creating, updating or removing multiple records at once has always been part of the Feathers adapter specification but it turned out to be quite easy to miss.

This means applications could be open to queries that a developer did not anticipate (like deleting or creating multiple records at once). Additionally, it could also lead to unexpected data in a hook that require special cases (like context.data or context.result being an array).

Now, multiple create, patch and remove calls (with the id value set to null) are disabled by default and have to be enabled explicitly by setting the multi option:

const service = require('feathers-<database>');

// Allow multi create, patch and remove
  multi: true

// Only allow create with an array
  multi: [ 'create' ]

// Only allow multi patch and remove (with `id` set to `null`)
  multi: [ 'patch', 'remove' ]

Important: When enabling multiple remove and patch requests, make sure to restrict the allowed query (e.g. based on the authenticated user id), otherwise it could be possible to delete or patch every record in the database.


Some database adapters allowed additional query parameters outside of the official Feathers query syntax. To reduce the risk of allowing malicious queries, only the standard query syntax is now allowed.

Non-standard query parameters (any query property starting with a $) will now throw an error. To allow them, they have to be explicitly whitelisted using the whitelist option:

const service = require('feathers-<database>');

// Allow multi create, patch and remove
  whitelist: [ '$regex' ]

Important: Be aware of potential security implications of manually whitelisted options. E.g. Enabling Mongoose $populate can expose fields that are normally protected at the service level (e.g. a users password) and have to be removed separately.