Track changes to your Sequelize models data. Perfect for auditing or versioning.

Downloads in past


91463.0.14 years ago8 years agoMinified + gzip package size for sequelize-paper-trail in KB


Sequelize Paper Trail
Help wanted: Please try out sequelize-paper-trail@3.0.0-rc.6 and give a šŸ‘/šŸ‘Ž here if it works as expected.

Track changes to your models, for auditing or versioning. See how a model looked at any stage in its lifecycle, revert it to any version, or restore it after it has been destroyed. Record the user who created the version.

node-version npm-version David() David()
GitHub release GitHub tag GitHub commits() npm-downloads

Table of Contents

- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Usage](#usage)
	- [Example](#example)
- [User Tracking](#user-tracking)
- [Options](#options)
	- [Default options](#default-options)
	- [Options documentation](#options-documentation)
- [Limitations](#limitations)
- [Testing](#testing)
- [Support](#support)
- [Contributing](#contributing)
- [Author](#author)
- [Thanks](#thanks)
- [Links](#links)


npm install --save sequelize-paper-trail
# or with yarn:
# yarn add sequelize-paper-trail

Note: the current test suite is very limited in coverage.


Sequelize Paper Trail assumes that you already set up your Sequelize connection, for example, like this:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password');

then adding Sequelize Paper Trail is as easy as:
const PaperTrail = require('sequelize-paper-trail').init(sequelize, options);

which loads the Paper Trail library, and the defineModels() method sets up a Revisions and RevisionHistory table.
Note: If you pass userModel option to init in order to enable user tracking, userModel should be setup before defineModels() is called.
Then for each model that you want to keep a paper trail you simply add:

hasPaperTrail returns the hasMany association to the revisionModel so you can keep track of the association for reference later.


const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password');

const PaperTrail = require('sequelize-paper-trail').init(sequelize, options || {});

const User = sequelize.define('User', {
  username: Sequelize.STRING,
  birthday: Sequelize.DATE

User.Revisions = User.hasPaperTrail();

User Tracking

There are 2 steps to enable user tracking, ie, recording the user who created a particular revision.
  1. Enable user tracking by passing userModel option to init, with the name of the model which stores users in your application as the value.

const options = {
  /* ... */
  userModel: 'user',
  1. Pass the id of the user who is responsible for the database operation to sequelize-paper-trail either by sequelize options or by using continuation-local-storage.

  /* ... */
}, {
}).then(() {
  /* ... */
const createNamespace = require('continuation-local-storage').createNamespace;
const session = createNamespace('my session');


  /* ... */
}).then(() {
  /* ... */

To enable continuation-local-storage set continuationNamespace in initialization options. Additionally, you may also have to call .run() or .bind() on your cls namespace, as described in the docs.

Disable logging for a single call

To not log a specific change to a revisioned object, just pass a noPaperTrail with a truthy (true, 1, ' ') value.
const instance = await Model.findOne();
instance.update({ noPaperTrail: true }).then(() {
  /* ... */


Paper Trail supports various options that can be passed into the initialization. The following are the default options:

Default options

// Default options
const options = {
  exclude: [
  revisionAttribute: 'revision',
  revisionModel: 'Revision',
  revisionChangeModel: 'RevisionChange',
  enableRevisionChangeModel: false,
  UUID: false,
  underscored: false,
  underscoredAttributes: false,
  defaultAttributes: {
    documentId: 'documentId',
    revisionId: 'revisionId'
  enableCompression: false,
  enableMigration: false,
  enableStrictDiff: true,
  continuationKey: 'userId',
  belongsToUserOptions: undefined,
  metaDataFields: undefined,
  metaDataContinuationKey: 'metaData'

Options documentation

| Option | Type | Default Value | Description | | --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | debug | Boolean | false | Enables logging to the console. | | exclude | Array | 'id', 'createdAt', 'updatedAt', 'deletedAt', 'createdat', 'updatedat', 'deletedat', options.revisionAttribute | Array of global attributes to exclude from the paper trail. | | revisionAttribute | String | 'revision' | Name of the attribute in the table that corresponds to the current revision. | | revisionModel | String | 'Revision' | Name of the model that keeps the revision models. | | tableName | String | undefined | Name of the table that keeps the revision models. Passed to Sequelize. Necessary in Sequelize 5+ when underscored is true and the table is camelCase or PascalCase. | | revisionChangeModel | String | 'RevisionChange' | Name of the model that tracks all the attributes that have changed during each create and update call. | | enableRevisionChangeModel | Boolean | false | Disable the revision change model to save space. | | UUID | Boolean | false | The revisionModel has id attribute of type UUID for postgresql. | | underscored | Boolean | false | The revisionModel and revisionChangeModel have 'createdAt' and 'updatedAt' attributes, by default, setting this option to true changes it to 'createdat' and 'updatedat'. | | underscoredAttributes | Boolean | false | The revisionModel has a defaultAttribute 'documentId', and the revisionChangeModel has a defaultAttribute 'revisionId, by default, setting this option to true changes it to 'documentid' and 'revisionid'. | | defaultAttributes | Object | { documentId: 'documentId', revisionId: 'revisionId' } | | | userModel | String | | Name of the model that stores users in your. | | enableCompression | Boolean | false | Compresses the revision attribute in the revisionModel to only the diff instead of all model attributes. | | enableMigration | Boolean | false | Automatically adds the revisionAttribute via a migration to the models that have paper trails enabled. | | enableStrictDiff | Boolean | true | Reports integers and strings as different, e.g. 3.14 !== '3.14' | | continuationNamespace | String | | Name of the name space used with the continuation-local-storage module. | | continuationKey | String | 'userId' | The continuation-local-storage key that contains the user id. | | belongsToUserOptions | Object | undefined | The options used for belongsTo between userModel and Revision model | | metaDataFields | Object | undefined | The keys that will be provided in the meta data object. { key: isRequired (boolean)} format. Can be used to privovide additional fields - other associations, dates, etc to the Revision model | | metaDataContinuationKey | String | 'metaData' | The continuation-local-storage key that contains the meta data object, from where the metaDataFields are extracted. |


  • This project does not support models with composite primary keys. You can work around using a unique index with multiple fields.


The tests are designed to run on SQLite3 in-memory tables, built from Sequelize migration files. If you want to actually generate a database file, change the storage option to a filename and run the tests.
npm test
# or with yarn:
# yarn test


Please use:


  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request


Ā© Niels van Galen Last ā€“ @nielsgl ā€“ Distributed under the MIT license. See `LICENSE` for more information.


This project was inspired by: