Only show guides for your app
Prisma, Sequelize, and Drizzle all work on the Node.js application — but each needs one Falix-specific step to survive the way servers start. Here's the tested truth for all three, and which to pick.
An ORM (Object-Relational Mapper) lets you write database code in JavaScript instead of raw SQL strings — models, types, and query builders instead of SELECT ... WHERE ?. The three popular Node choices are Prisma, Sequelize, and Drizzle, and the honest question isn't "which is best" but "which actually runs on a Falix server without surprises". Every claim below was tested in a container that starts your code exactly the way the Node.js application does. Short version: all three work — but two of them need one extra step you have to know about.
| At a glance | |
|---|---|
| You need | A server on the Node.js application |
| Plan | Any |
| Helps to know | Connect your app to a database and SQLite in depth |
The Node.js application runs npm install automatically on every start when a package.json exists — that's it. It does not run a build step, a code generator, or a database migration for you. Most ORM tutorials assume you'll type extra commands (prisma generate, prisma migrate, drizzle-kit push) in a terminal. On Falix there is no terminal for your server. So the rule is simple:
🎯 Good to know: Anything an ORM needs besides
npm installhas to run from apostinstallscript in yourpackage.json(which the automatic install triggers), or from a Git post-deploy command. This is the same build-on-install trick TypeScript uses on Node.
Keep that in mind and every ORM below becomes reliable. Ignore it and Prisma in particular will crash on first run.
Drizzle is a thin, type-safe query builder. Paired with better-sqlite3 it's the cleanest option here: better-sqlite3 ships prebuilt binaries (no compiler), and Drizzle itself is plain JavaScript with no code-generation step needed at runtime. Install drizzle-orm and better-sqlite3 from the Packages page. Your schema is ordinary JS:
// schema.js
const { sqliteTable, integer, text } = require('drizzle-orm/sqlite-core');
const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
score: integer('score').notNull().default(0),
});
module.exports = { users };
// index.js
const Database = require('better-sqlite3');
const { drizzle } = require('drizzle-orm/better-sqlite3');
const { users } = require('./schema');
const sqlite = new Database('app.db');
sqlite.exec(`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, score INTEGER NOT NULL DEFAULT 0
)`);
const db = drizzle(sqlite);
db.insert(users).values({ name: 'alice', score: 5 }).run();
console.log(db.select().from(users).all()); // [{ id: 1, name: 'alice', score: 5 }]
Creating tables with a plain CREATE TABLE IF NOT EXISTS on start keeps it self-contained. Drizzle's own migration tool, drizzle-kit, generates SQL migration files — but you run that on your own computer while developing and commit the result; it isn't needed on the server. Verdict: works with zero Falix-specific setup beyond installing the two packages.
Sequelize is the long-established ORM. With the sqlite3 package it works on the Node.js application out of the box — sqlite3 installs a prebuilt binary, and Sequelize's sync() creates your tables, so there's no separate codegen or migration step to wire in:
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize({ dialect: 'sqlite', storage: 'app.db', logging: false });
const User = sequelize.define('User', {
name: { type: DataTypes.STRING, allowNull: false },
score: { type: DataTypes.INTEGER, defaultValue: 0 },
});
(async () => {
await sequelize.sync(); // creates the table if missing
await User.create({ name: 'alice', score: 5 });
console.log(await User.findAll({ raw: true }));
})();
Install sequelize and sqlite3 from the Packages page. For a managed database instead of SQLite, swap the dialect (mysql with mysql2, or postgres with pg) and pass the connection string. Verdict: works; no build step required.
Prisma is the most feature-rich of the three, and the one people most often report "doesn't work" on hosts like this. It does work — the tested flow ran end-to-end — but only if you respect two facts:
prisma generate) that builds the client from your schema. It won't run by itself on Falix.The recipe that makes both automatic is a postinstall script — the automatic npm install runs it every start:
{
"scripts": {
"postinstall": "prisma generate && prisma db push --skip-generate --accept-data-loss"
},
"dependencies": { "@prisma/client": "^5.22.0" },
"devDependencies": { "prisma": "^5.22.0" }
}
With a normal prisma/schema.prisma (SQLite datasource) in place, pressing Start runs npm install → prisma generate builds the client → prisma db push creates the tables → your app runs. Tested result: a real prisma.user.create() followed by findMany() returned the inserted row on a clean server.
⚠️ Heads up:
prisma db pushon every start is fine for additive schema changes and solo projects. For anything you care about, generate real migrations locally and runprisma migrate deployas a Git post-deploy command instead —db pushcan drop columns to match the schema (that's what--accept-data-lossacknowledges).
If you skip the postinstall and just npm install, the app crashes with "@prisma/client did not initialize yet. Please run prisma generate" — that error is the missing step, not a broken host. Verdict: works, provided you wire in prisma generate (and a migration step).
| ORM | Status on the Node.js app | Falix-specific step | Best when |
|---|---|---|---|
| Drizzle + better-sqlite3 | ✅ Works, tested | None — pure JS + prebuilt binary | You want type-safety with the least friction |
| Sequelize + sqlite3 | ✅ Works, tested | None — sync() builds tables |
You like the mature, batteries-included style |
| Prisma | ✅ Works, tested | Required: postinstall: prisma generate (+ a migrate/push step); engine download on first install |
You want Prisma's schema, migrations, and studio and will set it up |
All three also drive a managed MySQL/PostgreSQL database — point them at the connection string from the Databases page instead of a SQLite file, keep it in .env, and the model code is unchanged.
💡 Tip: You don't need an ORM. For a bot or a small app,
better-sqlite3with hand-written SQL and?parameters (see SQLite in depth) is smaller, faster to start, and has nothing to generate. Reach for an ORM when types and migrations start earning their keep — not before.
Start the server and watch the Console. A working ORM prints the row it just inserted ({ name: 'alice', score: 5 } or similar). For Prisma specifically, the install log should show "Generated Prisma Client" and "Your database is now in sync" before your app output — if you don't see those two lines, the postinstall step didn't run.
@prisma/client did not initialize yet — the postinstall: prisma generate step is missing. Add it to package.json scripts and restart.node_modules afterward, so later starts are fast (until a reinstall wipes node_modules, when it downloads once more).Cannot find module 'sqlite3' / better-sqlite3 — the driver isn't installed. Add it from the Packages page and restart.sync(), Drizzle needs your CREATE TABLE (or a committed migration), Prisma needs db push/migrate deploy./home/container and are wiped on reinstall. Point the ORM at a managed database for data that must survive.For everything past getting them running, the official docs own the detail: prisma.io, sequelize.org, and orm.drizzle.team.