File structure

The anatomy of a Backfill integration and how the platform finds what each file does.

Every Backfill integration is a TypeScript project with a fixed layout. Hooks, jobs, API routes, custom entities, and fields are discovered by file path. UI pages are referenced from the manifest.

Required files

FilePurpose
backfill.config.tsManifest. defineExtension({...}) (or defineConnector({...})) as the default export.
package.jsonDeclare @backfill-io/sdk as a devDependency plus any browser-compatible runtime packages your scripts import.
tsconfig.jsonTypeScript config — strict: true, noEmit: true.
.backfillrcLocal dev credentials. Gitignored.
src/All script source.

What lives in src/

src/
├── hooks/<entity-kebab>/        Hooks for a given entity
│   ├── before-save.ts
│   ├── after-save.ts
│   └── recalculate.ts
├── jobs/                         Scheduled jobs
│   └── <name>.ts
├── api/                          HTTP routes
│   └── <path>.ts
├── entities/                     Custom entity definitions
│   └── <Name>.ts
├── fields/                       Field declarations for host entities
│   └── <EntityName>.ts
├── pages/                        UI pages and action handlers
│   └── <page>.tsx
└── lib/                          Shared helpers
    └── <Name>.ts 

Shared helpers usually live under src/lib. They are not registered on their own, but any hook, job, route, page, entity, tab, panel, or action can import them. The CLI bundles each executable entrypoint independently, so shared helper code is duplicated per entrypoint in v1.

Where each thing goes

To do this…Put a file at…What it exports
React to an entity create / updatesrc/hooks/<entity-kebab>/after-save.tsexport default async function (ctx) { ... }
Modify or reject an entity writesrc/hooks/<entity-kebab>/before-save.tsexport default async function (ctx) { return { ... } }
Contribute to draft calculationsrc/hooks/<entity-kebab>/recalculate.tsSee Hooks → Recalculate
Run on a schedulesrc/jobs/<name>.tsexport const schedule = "...", export async function run() {...}
Expose an HTTP endpointsrc/api/<path>.tsexport const GET = async (ctx) => {...} (or POST, PUT, PATCH, DELETE)
Define a custom entitysrc/entities/<PascalName>.tsexport default defineEntity({ name, fields })
Define fields on a host entitysrc/fields/<EntityName>.tsexport const stripeCustomerId = defineEntityField({ key: "stripe_customer_id", ... }) or defineLineField(...)
Add a dashboard pagesrc/pages/<name>.tsx + entry in pages[]A default-export render function
Add a tab / panel / actionA render .tsx + entry in ui.{tabs,panels,actions}Same as a page render