Best Practices
MasterRecord is flexible, but a few conventions keep your code fast, correct, and easy to reason about.
1. Always await writes#
Saving is asynchronous on MySQL and Postgres. Await every save() and saveChanges() so errors surface and ordering is guaranteed.
await user.save(); // ✅
await db.saveChanges(); // ✅
user.save(); // ❌ unhandled promise, lost errors2. Define fields as methods#
Columns are builder methods, not constructor properties. Object-literal “fields” are silently ignored by the schema builder.
name(db) { db.string().notNullable(); } // ✅
// this.name = { type: 'string' }; ❌ ignored3. Name the context file after the class#
The migration CLI resolves contexts by file name. Keep AppContext in app/models/AppContext.js so master db can find it.
4. Use relative SQLite paths#
connection: 'db/' resolves under your project root and auto-creates the file. A leading slash (/db/) is treated as a filesystem-absolute path.
5. Parameterize — never concatenate#
Bind values with $$. The query builder parameterizes them, eliminating injection.
db.User.where((u) => u.email == $$, email); // ✅ safe & parameterized6. Batch wisely#
Creating many rows? Save them through the same context and call saveChanges() once — MasterRecord builds an optimized batch insert that still runs your .set() transformers and relationships.
7. Index your foreign keys and filters#
Add .index() to columns you filter or join on frequently, and consider full-text indexes for searchable text.
.new() create · .save() persist one · saveChanges() persist all · .where().toList() read many · .single() read one · .remove()/.delete() remove.