JCC Express

Database

Prisma

Introduction

JCC Express MVC supports Prisma as an ORM option via DB_ORM=prisma. Prisma uses its own schema (prisma/schema.prisma), migrations, and generated client — separate from JCC Eloquent models in app/Models/.

You can also use Prisma alongside JCC Eloquent by keeping DB_ORM=jcc and configuring database.prisma.service in app/Config/database.ts (the framework still registers a singleton Prisma client).


Enable Prisma

Option A — Prisma as primary ORM

env
DB_ORM=prisma

DATABASE_URL="mysql://root:password@127.0.0.1:3306/your_database"
DATABASE_HOST=127.0.0.1
DATABASE_PORT=3306
DATABASE_USER=root
DATABASE_PASSWORD=password
DATABASE_NAME=your_database

DATABASE_URL is used by the Prisma CLI (prisma.config.ts). The framework does not pick a default runtime adapter. You must configure one explicitly (see below).

Built-in adapter factories (install the matching package when using PRISMA_ADAPTER or database.prisma.adapter):

PRISMA_ADAPTERPackage
mariadb@prisma/adapter-mariadb
postgres@prisma/adapter-pg + pg
sqlite@prisma/adapter-better-sqlite3 + better-sqlite3
libsql@prisma/adapter-libsql
env
PRISMA_ADAPTER=mariadb
DATABASE_URL="mysql://root:password@127.0.0.1:3306/your_database"

Or configure the adapter in PrismaService / database.prisma.adapter instead of PRISMA_ADAPTER.

Option B — Prisma alongside JCC Eloquent

Keep DB_ORM=jcc for Knex/JCC models and ensure app/Config/database.ts includes:

TypeScript
import { PrismaService } from "@/Services/PrismaService";

export const database = {
  orm: config.get("DB_ORM", "jcc"),
  prisma: {
    service: PrismaService,
  },
  // ...
};

PrismaServiceProvider registers the client whenever database.prisma.service is set.


Required packages

Bash
npm install @prisma/client @prisma/adapter-mariadb
npm install -D prisma

Initialize Prisma (new projects)

After installing the packages, scaffold Prisma in your app once from the project root. Skip this step if prisma/schema.prisma already exists.

Bash
bun --bun x prisma init --datasource-provider mysql --output ./generated/prisma

Equivalent with npx:

Bash
npx prisma init --datasource-provider mysql --output ./generated/prisma

This creates:

FilePurpose
prisma/schema.prismaYour Prisma schema
prisma.config.tsCLI config (DATABASE_URL, migrations path)

Use ./generated/prisma as the client output — not ../src/generated/prisma. JCC Express MVC imports the client from generated/prisma/client (see PrismaService below).

Set your database URL in .env before generating or migrating:

env
DATABASE_URL="mysql://root:password@127.0.0.1:3306/your_database"

Then add app/Services/PrismaService.ts and wire database.prisma.service in app/Config/database.ts (see App service class).


Generate the client

Generate the client after prisma init and whenever the schema changes:

Bash
bun artisanNode prisma:generate
# or
npm run prisma:generate

The generated client is written to generated/prisma/ (gitignored — run prisma:generate after clone/CI install).

Apply your first migration after generate:

Bash
bun artisanNode prisma:migrate init

App service class

The framework only injects an adapter when you set database.prisma.adapter or PRISMA_ADAPTER. Otherwise PrismaService owns the adapter:

TypeScript
import { PrismaClient } from "generated/prisma/client";
import { createMariaDbAdapter } from "jcc-express-mvc/lib/Database/Drivers/Prisma/adapters/mariadb";
import type { PrismaClientOptions } from "jcc-express-mvc/lib/Database/Drivers/Prisma/types";

export class PrismaService extends PrismaClient {
  constructor(options?: PrismaClientOptions) {
    super({
      adapter: options?.adapter ?? createMariaDbAdapter(), // your choice in the app
    });
  }
}

When the framework does inject an adapter (options.adapter), it takes precedence over your fallback.


Configuring an adapter

Choose one approach:

1. In PrismaService (app-owned — recommended when you want full control)

2. PRISMA_ADAPTER env — uses a built-in factory:

env
PRISMA_ADAPTER=postgres

3. database.prisma.adapter in app config:

TypeScript
import { createPostgresAdapter } from "jcc-express-mvc/lib/Database/Drivers/Prisma/adapters/
postgres";

export const database = {
  prisma: {
    service: PrismaService,
    adapter: () => createPostgresAdapter(),
  },
};

Fully custom — pass any Prisma 7 adapter instance or factory:

TypeScript
import { PrismaPg } from "@prisma/adapter-pg";
import { Pool } from "pg";

prisma: {
  service: PrismaService,
  adapter: () => new PrismaPg(new Pool({ connectionString: process.env.DATABASE_URL })),
},

database.prisma.adapter takes precedence over PRISMA_ADAPTER. If neither is set, the framework passes no adapter and PrismaService decides.


Framework adapter helpers

Built-in adapter factories:

ExportUse
createPrismaAdapter(name)Build adapter for a named driver (PRISMA_ADAPTER)
createMariaDbAdapter()MySQL / MariaDB
createPostgresAdapter()PostgreSQL
createSqliteAdapter()SQLite file
createLibSqlAdapter()LibSQL / Turso

The framework registers PrismaService as a singleton and aliases prisma and database.connection.


Using Prisma in controllers

Constructor injection (recommended):

TypeScript
import { Inject } from "jcc-express-mvc/Core/Dependency";
import { PrismaService } from "@/Services/PrismaService";

@Inject()
export class UsersController {
  constructor(private readonly prisma: PrismaService) {}

  async index() {
    return await this.prisma.user.findMany();
  }
}

Global helper:

TypeScript
const users = await prisma().user.findMany();

Schema and migrations

Schema: prisma/schema.prisma
Migrations: prisma/migrations/
CLI config: prisma.config.ts

Bash
# Create & apply a migration (development)
bun artisanNode prisma:migrate init

# Apply pending migrations (production)
bun artisanNode prisma:deploy

# Push schema without migration files (prototyping)
bun artisanNode prisma:push

# Open Prisma Studio
bun artisanNode prisma:studio

Equivalent npm scripts: prisma:generate, prisma:migrate, prisma:studio.


Framework wiring

PieceLocation
PrismaDriverjcc-express-mvc/lib/Database/Drivers/PrismaDriver.ts
Driver adaptersjcc-express-mvc/lib/Database/Drivers/Prisma/adapters/
PrismaServiceProviderjcc-express-mvc/lib/Database/PrismaServiceProvider.ts
Database resolverjcc-express-mvc/lib/Database/Database.ts (DB_ORM=prisma)

When DB_ORM=prisma (or when database.prisma.service is set in app/Config/database.ts):

  • Your PrismaService class is registered as a singleton.
  • The client is available via constructor injection, app.resolve("prisma"), or the global prisma() helper.
  • Knex / Sequelize / Mongoose setup is skipped so Prisma owns the database connection.
  • The client disconnects gracefully on shutdown.