{"id":12652,"library":"waterline","title":"Waterline ORM","description":"Waterline is an Object-Relational Mapper (ORM) for Node.js, designed to provide a uniform API for interacting with various data stores such as MySQL, PostgreSQL, MongoDB, Redis, and more, through a pluggable adapter system. While it is the default ORM within the Sails.js framework, it can also be used as a standalone library. The current stable version is 0.15.2, although its last publish date was over three years ago. A significant architectural shift occurred from v0.13 onwards, transitioning from callback-based APIs to fully embracing ECMAScript's `async/await` syntax for all query operations. Key differentiators include its consistent interface across diverse data stores, a strong emphasis on modularity and testability, and an ActiveRecord-inspired pattern tailored for modern JavaScript development, simplifying data persistence by abstracting database specifics behind declarative model definitions.","status":"active","version":"0.15.2","language":"javascript","source_language":"en","source_url":"git://github.com/balderdashy/waterline","tags":["javascript","mvc","orm","mysql","postgresql","redis","mongodb","active-record","waterline"],"install":[{"cmd":"npm install waterline","lang":"bash","label":"npm"},{"cmd":"yarn add waterline","lang":"bash","label":"yarn"},{"cmd":"pnpm add waterline","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Common in-memory/disk-based adapter used for quickstarts and local development; required for the quickstart example. Waterline ships without any adapters, so they must be installed separately.","package":"sails-disk","optional":false}],"imports":[{"note":"ESM import for modern Node.js environments. For older CommonJS (Node <13) or existing projects, use `require`.","wrong":"const Waterline = require('waterline');","symbol":"Waterline","correct":"import { Waterline } from 'waterline';"},{"note":"Collection is accessed as a static property of the `Waterline` class, not a direct named export.","wrong":"import { Collection } from 'waterline';","symbol":"Waterline.Collection","correct":"import { Waterline } from 'waterline';\n// ... then use Waterline.Collection.extend"},{"note":"Models are registered with and returned by the initialized Waterline instance via `collections`, not directly imported from the package.","wrong":"import { User } from 'waterline';","symbol":"Model instances (e.g., User)","correct":"const User = collections.user;"}],"quickstart":{"code":"import { Waterline } from 'waterline';\nimport DiskAdapter from 'sails-disk'; // Example adapter, install with `npm i sails-disk`\n\n// 1. Initialize Waterline\nconst waterline = new Waterline();\n\n// 2. Define a Collection (Model)\nconst UserCollection = Waterline.Collection.extend({\n  identity: 'user',\n  datastore: 'default',\n  primaryKey: 'id',\n\n  attributes: {\n    id: { type: 'number', autoIncrement: true },\n    name: { type: 'string', required: true },\n    email: { type: 'string', unique: true },\n    age: { type: 'number', defaultsTo: 18 },\n  },\n});\n\n// 3. Register the Collection\nwaterline.registerModel(UserCollection);\n\n// 4. Configure Waterline\nconst config = {\n  datastores: {\n    default: {\n      adapter: 'sails-disk',\n    },\n  },\n  models: {\n    migrate: 'alter', // 'safe', 'alter', 'drop'\n  }\n};\n\nasync function runWaterlineExample() {\n  try {\n    // 5. Initialize the ORM\n    const { collections, connections } = await waterline.initialize(config);\n\n    // Access the User model\n    const User = collections.user;\n\n    // Create a new user\n    const newUser = await User.create({ name: 'Alice', email: 'alice@example.com' }).fetch();\n    console.log('Created user:', newUser);\n\n    // Find all users\n    const allUsers = await User.find();\n    console.log('All users:', allUsers);\n\n    // Update a user\n    const updatedUser = await User.updateOne({ id: newUser.id })\n                                  .set({ age: 30 })\n                                  .fetch();\n    console.log('Updated user:', updatedUser);\n\n    // Clean up (release connections)\n    await waterline.teardown();\n  } catch (err) {\n    console.error('Waterline error:', err);\n  }\n}\n\nrunWaterlineExample();","lang":"typescript","description":"This quickstart demonstrates how to use Waterline standalone with a `sails-disk` adapter. It covers initializing Waterline, defining a simple model, performing basic CRUD operations using `async/await` syntax, and tearing down the ORM gracefully. This setup is typical for standalone Waterline applications or for testing environments."},"warnings":[{"fix":"Refactor all query operations to use `await` or `.then().catch()` for promise-based handling. The `.fetch()` method is often needed to retrieve results from `create` and `update` operations.","message":"Starting with Waterline v0.13, the API transitioned from callback-based methods to `async/await` (promises). Existing code relying on `.exec(callback)` will break.","severity":"breaking","affected_versions":">=0.13.0"},{"fix":"After a `.save()` operation, if you need the updated record, perform a subsequent `.findOne()` or `.find()` query to retrieve the current state of the data.","message":"Waterline v0.11.0 removed the second argument from `.save()` commands that previously returned the newly updated data. This change was for performance optimization.","severity":"breaking","affected_versions":">=0.11.0"},{"fix":"Upgrade to Waterline v0.12.2 or higher immediately. Carefully review and backup your data before running migrations with the updated version, especially in production environments.","message":"Waterline v0.12.2 fixed critical issues with compatibility in `alter` auto-migrations which were causing corrupted data, especially in SQL adapters. Older versions might have led to data integrity problems.","severity":"breaking","affected_versions":"<0.12.2"},{"fix":"Ensure your Waterline version matches the requirements of your Sails.js project. Refer to the Sails.js documentation for specific compatibility matrices to avoid unexpected behavior and errors.","message":"Sails.js framework versions have specific Waterline compatibility. Sails v0.12 uses Waterline 0.11.x, whereas Sails v1.0 and later use Waterline v0.13+ (which includes the `await` syntax).","severity":"gotcha","affected_versions":"*"},{"fix":"If operating in schemaless mode and encountering problems with `id`-based queries, ensure you are on Waterline `v0.12.1` or `v0.11.2` (or newer patch versions) to benefit from the fixes.","message":"Issues were reported and fixed in `v0.12.1` and `v0.11.2` related to searching by `id` in schemaless mode, which could lead to incorrect results or errors.","severity":"gotcha","affected_versions":"<0.12.1 || <0.11.2"},{"fix":"Avoid reusing or modifying criteria objects after passing them to Waterline methods if their original state is needed. For aggregations, use the new dedicated model methods instead of criteria clauses. Ensure criteria are structured correctly: `{ where: { field: 'value' }, limit: 4 }` instead of mixed top-level properties.","message":"In Waterline v0.13, criteria objects passed into model methods (e.g., `update`, `createEach`) will be mutated in-place for performance. This was not always the case in v0.12. Also, aggregation clauses (`sum`, `average`, `min`, `max`, `groupBy`) are no longer supported in criteria.","severity":"breaking","affected_versions":">=0.13.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Remove `.exec(cb)` and use `await` before the query, or chain `.then().catch()` to handle the promise. Remember to add `.fetch()` for `create`, `update`, and `destroy` operations to retrieve the record(s).","cause":"Attempting to use the old callback pattern (e.g., `.exec(cb)`) on a query after Waterline's transition to `async/await` (from v0.13).","error":"TypeError: callback is not a function"},{"fix":"Install the required adapter package (e.g., `npm install sails-mysql`) and ensure it's imported and explicitly registered in the `config.datastores` object before `waterline.initialize()`.","cause":"The specified adapter was not correctly installed or registered with the Waterline instance during initialization. Waterline does not ship with adapters.","error":"Error: Adapter 'my-adapter' not registered."},{"fix":"Ensure Waterline is fully initialized (`await waterline.initialize(config)`), and then access your models through the returned `collections` object, typically like `const MyModel = collections.mymodel;`.","cause":"Trying to access a Waterline model (e.g., `MyModel.find()`) directly without proper initialization or scoping. Models are exposed via the initialized Waterline instance.","error":"ReferenceError: MyModel is not defined"},{"fix":"Implement error handling for uniqueness violations. Before creating, check if the record exists, or catch the specific error type after the operation and handle it gracefully (e.g., notify the user).","cause":"Attempting to create or update a record with a value that violates a uniqueness constraint defined in the model's attributes (e.g., a duplicate email for a `unique: true` field).","error":"Error: A record with that unique key already exists."}],"ecosystem":"npm"}