Skip to content
beta

Commands and Scaffold

The Harpia Framework provides a set of commands to streamline development. These commands are defined in the package.json file:

CommandDescription
startStarts the application.
devStarts the application in development mode with hot-reloading.
testsRuns tests for a specific module or directory (e.g., user/store).
lintRuns lint for a specific module or file (e.g., user/controller/store).
gGenerates modules, files, and other scaffolding components.
studioStarts Prisma Studio for database management.
seedRuns database seed scripts.
migrateGenerates prisma client types and applies all pending database migrations.
deployGenerates prisma client types and applies all pending database migrations.

You can run the tests command like bun tests user to execute all tests within the user module. To run tests sequentially, add the --runInBand flag, for example: bun tests user --runInBand.

The lint command can be used on a specific module, directory, or file. For example:

  • bun lint user lints the entire user module.
  • bun lint user/controller lints the controller directory within the user module.
  • bun lint user/controller/store lints a specific file.

The Harpia Framework includes a powerful scaffolding system to help you generate commonly used application components with ease. This tool accelerates development and enforces a consistent structure across your codebase.

You can invoke the scaffolding tool using the following command:

Terminal window
bun g

Or if you prefer, you can use the shorthand:

Terminal window
bun g <type>

Where <type> can be one of the following:

  • module
  • controller
  • test
  • factory
  • seed
  • task
  • validation
  • observer

Upon execution, you’ll be prompted to select what you want to generate:

Terminal window
? What do you want to forge? (Use arrow keys)
Module
Controller
Test
Factory
Seed
Task
Validation
Observer

Or you can specify the type directly:

Terminal window
bun g module

The Module option scaffolds a complete directory structure for a new feature or resource in your application. A typical module includes controllers, views, services, tests, and more, organized as follows:

  • Directoryyour-module-name
    • Directorycontrollers
      • index.ts
      • create.ts
      • destroy.ts
      • edit.ts
      • list.ts
      • show.ts
      • store.ts
      • update.ts
    • Directorypages
      • Directorycreate
        • page.html
      • Directoryedit
        • page.html
      • Directorylist
        • page.html
      • Directoryshow
        • page.html
    • Directoryrepositories
      • index.ts
      • create.ts
      • destroy.ts
      • list.ts
      • show.ts
      • update.ts
    • Directoryservices
      • index.ts
      • create.ts
      • destroy.ts
      • list.ts
      • show.ts
      • update.ts
    • Directorytests
      • .gitignore
    • Directoryvalidations
      • index.ts
      • create.ts
      • update.ts
    • your-module-name.routes.ts

🛠️ Note: The pages/ directory is only generated if the application is running in MODE=fullstack. If the mode is set to MODE=api, the pages/ directory will not be included.

This layout promotes modular development, making your application easier to scale and maintain by clearly separating responsibilities.

Harpia lets you scaffold generic controller files with just one command:

Terminal window
bun g controller

Choose the Test option, then specify the module and test name.
Example:

Terminal window
Module name: user
Controller name: generic

This creates a new file at:
modules/user/controllers/generic.ts

Harpia lets you scaffold ready-to-use test files with just one command:

Terminal window
bun g

Choose the Test option, then specify the module and test name.
Example:

Terminal window
What do you want to forge? Test
Module name: user
Test name: store

This creates a new file at:
modules/user/tests/store.spec.ts

Each test file comes pre-configured with bun:test and the TestClient utility to help you get started quickly.

🔗 Learn more: Test Documentation

The Factory option scaffolds a factory class used to generate seed data for your models.
To create a new factory, run the command:

Terminal window
bun g

Then choose the Factory option:

Terminal window
? What do you want to forge? (Use arrow keys)
Module
Controller
Test
Factory
Seed
Task
Validation
Observer

You’ll be prompted to enter a factory name, typically matching the model it’s for:

Terminal window
What do you want to forge? Factory
Factory name (use a model name): user

This will generate a new file at:
app/database/factories/user.factory.ts

The generated file comes with a base structure like this:

import { Factory } from "app/helpers/Factory";
import { User } from "..";
const UserFactory = new Factory().define(User, (faker) => {
return {
/**
* Define your model fields here using faker.js.
*
* Example:
* name: faker.person.fullName(),
*/
};
});
export { UserFactory }

Factories include five core methods:

  • .create() – Creates and persists one record to the database.
  • .createMany(count) – Creates and persists multiple records.
  • .makeStubbed() – Generates one record’s data without saving it.
  • .makeStubbedMany(count) – Generates multiple records’ data without saving.
  • .merge(data) – Merges custom fields with generated data (works with all other methods).

Here’s an example of how to use a factory:

import { UserFactory } from "app/database/factories/user.factory";
await UserFactory.create();
await UserFactory.createMany(2);
const user = await UserFactory.makeStubbed();
const users = await UserFactory.makeStubbedMany(5);
await UserFactory.merge({ name: "John Doe" }).create();
const customUser = await UserFactory.merge({ name: "John Doe" }).makeStubbed();

💡 You can use factories in your tests and seeders to generate reliable and consistent mock data during development.

Seeding is the process of populating your database with initial data — useful for development, testing, or simply bootstrapping your application with some default content.
Harpia provides a powerful and flexible seeding system that integrates seamlessly with factories, allowing you to generate realistic data with ease.

You can generate seed files using the bun g command, or create them manually for full control over the data flow.

📖 Check out the full seeding guide to learn how to create, run, and structure your seed files effectively.

Harpia supports background processing and scheduled tasks using the powerful cron library. Tasks are placed in the app/tasks directory and can be easily scaffolded using the bun g command.

Each task is a CronJob instance and runs on a schedule you define — perfect for background processing, database cleanup, notifications, and more.

📖 For a complete walkthrough, check the full guide on Tasks and Jobs.

Harpia uses the Zod library for schema-based validation, providing a powerful and type-safe way to ensure that data conforms to expected formats before processing.

You can generate a custom validation file using the bun g command:

Terminal window
bun g

Then select the Validation option:

Terminal window
? What do you want to forge? (Use arrow keys)
Module
Controller
Test
Factory
Seed
Task
Validation
Observer
Module name: user
Validation name: create

This will generate a new file at:

modules/user/validations/create.ts

With the following structure:

import AppError from "app/helpers/AppError";
import * as z from "zod";
export const Schema = z.object({
// name: z.string().min(1).max(255),
});
export type SchemaType = z.infer<typeof Schema>;
export async function create(data: SchemaType) {
try {
Schema.parse(data);
} catch (error) {
if (error instanceof z.ZodError || error instanceof AppError) {
throw error;
}
throw AppError.E_GENERIC_ERROR("Unexpected error during validation.");
}
}

When generating a new Module using bun g, Harpia automatically creates two default validation files:

  • create.ts
  • update.ts

These files are located in:

modules/[module]/validations/

They are also automatically exported through the module’s index.ts file:

import { create } from "./create";
import { update } from "./update";
export const validation = {
create,
update,
};

This structure makes it easy to reuse validation logic consistently across your controllers or services.


💡 Tip: You can enhance your validations using Zod features like .refine(), .superRefine(), .transform(), or schema composition for advanced use cases.

Harpia provides a simple and powerful way to hook into Prisma lifecycle events using Observers. These let you react to model-level database operations such as create, update, delete, and more.

Observers live in the app/observers directory and are automatically registered when the application boots.

You can scaffold a new observer with:

Terminal window
bun g

Use observers to:

  • Log database activity
  • Send notifications or emails
  • Sync data with external APIs or services

Each observer is defined by attaching a callback to a Prisma operation on a specific model:

app/observers/user.observer.ts
import { Observer } from ".";
Observer.model("User", "create", ({ data }) => {
console.log("New user created:", data);
});

🔗 Learn more: Observer Documentation

Harpia supports secure, session-based authentication out of the box.

Use this command to scaffold the necessary files:

Terminal window
bun g --config session

🔐 Full setup guide: Authentication Guide