Database
Netpress no longer treats the database layer as “SQL first with optional extras.” The starter now supports MongoDB and SQL through one shared model, migration, and seeder structure, while the framework resolves the correct runtime internally.
Quick Example
// config/database.js
export default {
default: process.env.DB_CONNECTION || "mongo",
// Opened at boot. Empty = fully lazy (connections open on first use).
preload: [],
connections: {
mongo: {
uri: process.env.MONGO_URI || "mongodb://localhost:27017/netpress",
},
mysql: {
host: process.env.DB_HOST || "127.0.0.1",
port: parseInt(process.env.DB_PORT, 10) || 3306,
database: process.env.DB_DATABASE || "netpress",
username: process.env.DB_USERNAME || "root",
password: process.env.DB_PASSWORD || "",
dialect: "mysql",
},
postgres: {
host: process.env.DB_HOST || "127.0.0.1",
port: parseInt(process.env.DB_PORT, 10) || 5432,
database: process.env.DB_DATABASE || "netpress",
username: process.env.DB_USERNAME || "root",
password: process.env.DB_PASSWORD || "",
dialect: "postgres",
},
sqlite: {
storage: process.env.DB_SQLITE_PATH || ":memory:",
dialect: "sqlite",
},
},
};
How The Starter Boots The Database
DatabaseServiceProvider registers the manager with registerApplicationDatabase(...) during boot. This:
- Seeds placeholders in the connection registry for every configured connection
- Discovers shared models from
app/Models/(file imports only — no query runs) - Does not open any real database connections unless a name appears in
preload
Real connections are opened lazily on first use (see Hybrid Bootstrap):
Model.query()/Model.find(...)/ etc.DB.connection(name)/DB.table(...)/DB.collection(...)DB.transaction(...)- Migration and seeder CLI commands
The starter also exposes a small helper object:
db.typedb.connectiondb.model(name)db.transaction(callback, name)db.table(name)db.collection(name)
db.model(name) resolves the same model class you would normally import, but by name at runtime. The other methods proxy into the shared core DB facade, so you can still reach transactions or ad-hoc table and collection queries from starter code when needed. For named connections, use the core DB.connection(name) facade directly.
Shared Application Structure
These are the default database-facing folders now:
app/Models/database/migrations/database/seeders/
Legacy driver-specific folders are fallback-only and should not be used for new work.
Connection Resolution
Each model resolves its own driver and connection:
- If the model sets
static connection, Netpress uses that connection or driver. - Otherwise the model resolves against the active
DB_CONNECTION. - SQL connections normalize to the SQL runtime.
mongonormalizes to the MongoDB runtime.
That means the same application API works across drivers:
import User from "../app/Models/User.js";
const user = await User.find(1);
const admins = await User.where({ role: "admin" }).paginate(1, 20);
DB Facade
Most application code should stay on shared models, but Netpress now exposes a first-class core DB facade for ad-hoc table access, named connections, raw SQL, and transactions.
import { DB } from "@admicaa/netpress";
const activeUsers = await DB.table("users")
.where("status", "active")
.latest("createdAt")
.get();
const rows = await DB.select(
"select count(*) as total from users where role = ?",
["admin"],
);
The ad-hoc table() and collection() helpers use the same hardened shared query builder as models, so they inherit the existing identifier and value safety checks.
Transactions
DB.transaction() scopes model writes and ad-hoc table queries to the active transaction.
import { DB } from "@admicaa/netpress";
import User from "../app/Models/User.js";
await DB.transaction(async (trx) => {
const user = await User.create({
name: "Ada Lovelace",
email: "ada@example.com",
password: "secret",
});
await trx.table("users")
.where("id", user.id)
.update({ role: "admin" });
});
You can also target a named connection explicitly:
await DB.transaction(async () => {
// ...
}, "mysql");
On SQL connections, the callback runs inside a real Knex transaction. On MongoDB connections, Netpress starts a session transaction and pushes that session through the shared model and query runtime.
Safety Notes
DB.table()andDB.collection()reject unsafe table, collection, column, operator, sort, and pagination expressions.DB.select(),DB.statement(),DB.update(), andDB.delete()keep parameter binding separate from SQL and reject obvious unsafe fragments such as statement chaining and SQL comments.- Query builder protections still apply to
Model.where(...),DB.table(...).where(...), and Mongo filters built through the shared runtime.
Lazy vs Preloaded Connections
By default the starter opens zero database sockets at boot. That is correct for most apps — connections get built on first use, only for the databases actually touched by the current request or CLI command.
To fail-fast at boot (e.g. in production, on a specific primary DB), add names to preload:
// config/database.js
export default {
default: "mysql",
preload: ["mysql"], // warm the primary at boot
connections: { /* ... */ },
};
Or via environment variable:
DB_PRELOAD=mysql,analytics node server.js
Multi-connection apps behave the same way: each named connection is opened independently on first use, or eagerly when listed in preload.
class AuditLog extends BaseModel {
static table = "audit_logs";
static connection = "analytics"; // opened on first AuditLog query
}
SQLite For Tests
The starter treats in-memory SQLite as a first-class test runtime. When DB_CONNECTION=sqlite and the configured storage is :memory:, add sqlite to preload so the connection opens at boot — migrations are auto-run against in-memory SQLite during preload so tests can execute without an external database service.
// config/database.js (test env)
export default {
default: "sqlite",
preload: ["sqlite"],
connections: {
sqlite: { storage: ":memory:", dialect: "sqlite" },
},
};
Database Commands
npm run artisan -- migrate
npm run artisan -- migrate --seed
npm run artisan -- migrate:rollback --step=1
npm run artisan -- migrate:fresh --seed
npm run artisan -- migrate:refresh --seed
npm run artisan -- migrate:status
npm run artisan -- db:seed
npm run artisan -- db:seed --seeder=UserSeeder
These commands now read the configured connections and migration plan. They do not take runtime --connection flags the way the older docs described.