App Composition

Structure larger projects with defineChimpbaseApp.

For larger projects, compose your app in a chimpbase.app.ts file using defineChimpbaseApp:

import { defineChimpbaseApp } from "@chimpbase/bun";
import { subscription, worker, cron } from "@chimpbase/runtime";

import migrations from "./chimpbase.migrations.ts";
import { createCustomer, listCustomers } from "./src/modules/customers.ts";
import { syncCustomer } from "./src/modules/sync.ts";

export default defineChimpbaseApp({
  project: { name: "my-app" },
  migrations,
  registrations: [
    createCustomer,
    listCustomers,
    subscription("customer.created", syncHandler, {
      idempotent: true,
      name: "enqueueSync",
    }),
    worker("customer.sync", syncCustomer),
    cron("reports.daily", "0 9 * * *", generateDailyReport),
  ],
});

Run with:

bun run chimpbase.app.ts

What goes in defineChimpbaseApp

OptionPurpose
project.nameProject identifier used for internal table namespacing
migrationsDatabase migration definitions for your application tables
registrationsArray of actions, subscriptions, workers, cron jobs, and workflows
httpHandlerOptional HTTP handler (e.g. a Hono app) for REST endpoints

Registrations

All primitives go in a single registrations array. Actions are registered by their export name; subscriptions, workers, and cron jobs are created inline:

const registrations = [
  // Actions (name inferred from export)
  createProject,
  listProjects,
  createTodo,

  // Subscriptions
  subscription("todo.created", auditTodoCreated, {
    idempotent: true,
    name: "auditTodoCreated",
  }),

  // Workers
  worker("todo.notify", notifyTodoCompleted),
  worker("todo.notify.dlq", captureDlq, { dlq: false }),

  // Cron
  cron("backlog.snapshot", "*/15 * * * *", captureSnapshot),
];

Decorator alternative

If you prefer a class-based style, use decorators and collect registrations with registrationsFrom(...):

import { Action, Subscription, Worker, Cron } from "@chimpbase/runtime";
import { registrationsFrom } from "@chimpbase/bun";

class TodoModule {
  @Action({ args: v.object({ title: v.string() }) })
  async createTodo(ctx, input) { /* ... */ }

  @Subscription("todo.created", { idempotent: true })
  async auditTodoCreated(ctx, event) { /* ... */ }

  @Worker("todo.notify")
  async notifyTodoCompleted(ctx, payload) { /* ... */ }

  @Cron("backlog.snapshot", "*/15 * * * *")
  async captureSnapshot(ctx, invocation) { /* ... */ }
}

export default defineChimpbaseApp({
  project: { name: "my-app" },
  registrations: registrationsFrom(TodoModule),
});