Logotipo Hedhog

Get Hedhog updates in your inbox

New releases, fresh recipes, and breaking changes — no spam.

Module Development

Modules are how you extend a HedHog project. Instead of hand-writing SQL, controllers, DTOs, and permission tables, you describe a table in YAML and let the CLI generate the migration, a full CRUD API, and the route/role permissions that guard it. This guide walks that flow end to end by building a small catalog module with a product table.

By the end you will have:

  • a new library scaffolded under libraries/,
  • a product table defined in YAML and applied through a migration,
  • a working CRUD API with route-level permissions,
  • and an admin page to manage records.

Development Flow

  1. Create the library.
  2. Define the table in YAML.
  3. Generate and apply the migration.
  4. Seed initial data (optional).
  5. Synchronize route and role permissions.
  6. Build the admin/frontend experience.

1. Create the library

Scaffold a new library with the CLI, then install so the workspace picks it up:

hedhog dev create-library --name catalog
pnpm install

This creates libraries/catalog/ with the standard hedhog/ directory (table/, data/, query/, frontend/) and wires the package into the monorepo.

2. Define the table in YAML

A table lives in libraries/<library>/hedhog/table/<table>.yaml. The file name, in snake_case, becomes the PostgreSQL table name — so product.yaml creates a product table.

# libraries/catalog/hedhog/table/product.yaml
columns:
  - type: pk
  - name: name
  - name: price
    type: decimal
    precision: 12
    scale: 2
  - type: created_at
  - type: updated_at

What each line does:

LineMeaning
type: pkSerial id primary key. Always prefer this over isPrimaryKey.
name: nameA "bare" column with no type is an implicit VARCHAR — a common repo convention.
type: decimal + precision/scaleA DECIMAL(12, 2) money column.
type: created_at / updated_atTIMESTAMPTZ audit columns. updated_at also gets a trigger that refreshes it on every UPDATE.

3. Generate and apply the migration

When a library is added, the CLI runs this pipeline:

  1. Scan libraries/<library>/hedhog/table/ for schema definitions — one file per table.
  2. Pair each table with its seed data in hedhog/data/ (matched by file name).
  3. Generate a PostgreSQL migration (CREATE TABLE, indexes, FK constraints, INSERTs) under apps/api/prisma/migrations/.
  4. Apply the migration through Prisma.
hedhog add catalog

4. Seed initial data (optional)

Seed rows go in libraries/<library>/hedhog/data/<table>.yaml, matched to the table by file name. Each list entry is one row:

# libraries/catalog/hedhog/data/product.yaml
- name: Starter plan
  price: 19.90
- name: Pro plan
  price: 49.90

The id, created_at, and updated_at columns are filled automatically, so you only list the business columns.

5. Synchronize route and role permissions

The CRUD endpoints are protected by route permissions. Two files keep them in sync — both under libraries/<library>/hedhog/data/.

Declare the library admin role in role.yaml:

# libraries/catalog/hedhog/data/role.yaml
- slug: admin-catalog
  name:
    en: Catalog Administrator
    pt: Administrador de Catálogo
  description:
    en: Administrator with full access to catalog management.
    pt: Administrador com acesso total à gestão de catálogo.

Then map each endpoint to the roles that may call it in route.yaml. Always include the global admin role plus the library-specific admin-catalog role:

# libraries/catalog/hedhog/data/route.yaml
- url: /product
  method: GET
  relations:
    role:
      - where:
          slug: admin
      - where:
          slug: admin-catalog
- url: /product
  method: POST
  relations:
    role:
      - where:
          slug: admin
      - where:
          slug: admin-catalog

6. Build the admin experience

With the API and permissions in place, add the admin page that lists and edits records. A standard list page uses a PageHeader, a KPI row, a flat search/filter toolbar with a table or cards view, and a pagination footer — with a sheet-based form for create/edit. Reuse the shared primitives (EntityPicker, useFormDraft, ResizableSheetContent, the KPI and search components) rather than building local variants.

After you add or change admin pages and their message files, sync them back into the library:

hedhog dev assets-to-library catalog
  • Keep architecture boundaries clear: business logic in libraries/*, entrypoints in apps/*, shared utilities in packages/*.
  • Reuse shared components before creating local variants.
  • Keep route.yaml/role.yaml synchronized with the live endpoints.
  • Validate focused lint/build/tests for the areas you touched.

Next steps