Databases
xpress-generator supports four databases. Each one generates a dedicated config file, model, service layer, migration files, and a ready-to-use docker-compose.yml automatically.
MongoDB
Uses Mongoose as the ODM.
Generated files
| File | Description |
|---|---|
src/config/config-mongo.js | Connects via mongoose.connect() |
src/modules/{name}/{name}Model.js | Mongoose schema with timestamps |
src/modules/auth/RefreshToken.js | TTL-indexed refresh token model |
Environment variables
MONGO_URI=mongodb://localhost:27017/myapp
Docker
# docker-compose.yml (excerpt)
mongo:
image: mongo:7
ports: ['27017:27017']
volumes: [mongo_data:/data/db]
healthcheck:
test: ['CMD', 'mongosh', '--eval', 'db.adminCommand("ping")']
docker compose up
Migrations
MongoDB is schema-less — no migrations needed. Mongoose creates collections automatically when you insert the first document.
The RefreshToken model uses a TTL index (expires: 7d) so tokens are automatically deleted from the database when they expire — no manual cleanup needed.
MySQL
Uses Sequelize ORM with the mysql2 driver.
Generated files
| File | Description |
|---|---|
src/config/config-mysql.js | Sequelize instance with connection pool |
src/config/sequelize.js | Sequelize CLI configuration (reads from .env) |
src/modules/{name}/{name}Model.js | sequelize.define() model |
src/modules/auth/RefreshToken.js | Sequelize refresh token model |
.sequelizerc | Points CLI to db/migrations/ and src/config/sequelize.js |
db/migrations/{ts}-create-{name}.js | Initial migration: creates the {name}s table |
Environment variables
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_DATABASE=myapp
MYSQL_USER=dev
MYSQL_PASSWORD=devpass
Migrations
# Apply all pending migrations
npm run db:migrate
# Roll back the last migration
npm run db:migrate:undo
Migration files are tracked automatically by Sequelize CLI in the SequelizeMeta table. Running db:migrate multiple times is safe — already-applied files are skipped.
Docker
docker compose up
The generated docker-compose.yml starts MySQL 8 with a healthcheck. The app waits for MySQL to be ready before starting (depends_on with condition: service_healthy).
# docker-compose.yml (excerpt)
mysql:
image: mysql:8
environment:
MYSQL_DATABASE: myapp
MYSQL_USER: dev
MYSQL_PASSWORD: devpass
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 10s
retries: 10
The generated config does NOT call sequelize.sync(). Use migrations to manage schema changes. Only use sequelize.sync({ alter: true }) in local development if needed, and never { force: true } with real data.
PostgreSQL
Uses Sequelize ORM with the pg and pg-hstore drivers.
Generated files
| File | Description |
|---|---|
src/config/config-postgres.js | Sequelize instance pointing to PostgreSQL |
src/config/sequelize.js | Sequelize CLI configuration |
src/modules/{name}/{name}Model.js | sequelize.define() model |
src/modules/auth/RefreshToken.js | Sequelize refresh token model |
.sequelizerc | Points CLI to db/migrations/ |
db/migrations/{ts}-create-{name}.js | Initial migration |
Environment variables
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_DATABASE=myapp
POSTGRES_USER=dev
POSTGRES_PASSWORD=devpass
Migrations
Identical to MySQL:
npm run db:migrate # apply pending
npm run db:migrate:undo # roll back last
Docker
docker compose up
# docker-compose.yml (excerpt)
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U dev -d myapp']
The generated configuration is identical to MySQL except for dialect: 'postgres' and the env variable names. All Sequelize knowledge transfers directly.
SQL Server
Uses mssql directly (no ORM).
Generated files
| File | Description |
|---|---|
src/config/config-sqlserver.js | mssql connection pool |
src/modules/{name}/{name}Model.js | Repository pattern with raw SQL queries |
src/modules/auth/RefreshToken.js | mssql-based refresh token model |
db/migrations/{ts}-create-{name}.sql | Raw SQL migration with IF NOT EXISTS guard |
db/migrate.js | Custom migration runner |
Environment variables
DB_SERVER=localhost
DB_NAME=myapp
DB_USER=sa
DB_PASSWORD=Dev@Pass123
Migrations
npm run db:migrate
The custom runner (db/migrate.js):
- Creates a
_migrationstable if it doesn't exist - Reads all
.sqlfiles indb/migrations/sorted by name - Skips already-applied files
- Runs new files and records them in
_migrations
Running db:migrate multiple times is safe — applied files are tracked and skipped.
Docker
docker compose up
# docker-compose.yml (excerpt)
sqlserver:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
ACCEPT_EULA: 'Y'
MSSQL_SA_PASSWORD: Dev@Pass123
MSSQL_PID: Developer
healthcheck:
test: ['CMD-SHELL', '/opt/mssql-tools/bin/sqlcmd -S localhost -U sa ...']
interval: 15s
retries: 10
SQL Server enforces strong passwords by default. The password must contain uppercase, lowercase, digit, and special character, and be at least 8 characters. Dev@Pass123 satisfies this.
Repository pattern
Because mssql has no ORM, the generated model uses explicit parameterized SQL queries:
async function create(data) {
const pool = await getPool();
const request = pool.request();
request.input('name', mssql.NVarChar, data.name);
request.input('email', mssql.NVarChar, data.email);
const result = await request.query(
'INSERT INTO items (name, email) OUTPUT INSERTED.* VALUES (@name, @email)'
);
return result.recordset[0];
}
Working with migrations after generate:model
Every time you run generate:model, a new timestamped migration file is created alongside the module:
npx xpress-generator generate:model Invoice
# creates:
# src/modules/invoice/...
# db/migrations/1712345678-create-invoice.js (MySQL/PostgreSQL)
# db/migrations/1712345678-create-invoice.sql (SQL Server)
Then apply it:
npm run db:migrate