Working on the API
This page is for contributors working on Lombok’s backend — the NestJS API
in packages/api that acts as Lombok’s control plane.
It covers where API code lives, how the API fits into Lombok’s runtime boundaries, and how to run the relevant checks locally. It does not repeat environment setup — for that, start with Local Development with dx.
Two different kinds of “backend work.” Contributing to the core API / control plane (this page) is different from writing the backend logic of an app that runs on top of the platform. If you are building an app’s backend, skip to Core API work vs. app-level backend work.
Where API work lives
Section titled “Where API work lives”Lombok is a Bun workspace monorepo, so backend work is not in a single
src/ folder. The main anchors are:
packages/api— the main NestJS backend and control planepackages/types— shared contracts and types used across runtime boundariespackages/sdk— the typed client SDK built around the platform API contract
Per the Repository Conventions routing
guide, the rule is direct: backend logic, auth, storage, tasks, sockets, and
platform services → packages/api.
What the API is responsible for
Section titled “What the API is responsible for”Following the Package Map, packages/api is the
control plane and owns concerns including:
- auth and users
- folders, storage, and object metadata
- events and tasks
- app platform services and app configuration
- Docker integration
- comments, search, and notifications
- sockets (realtime gateways)
- MCP
- ORM integration
The Architecture Overview frames this package as the control plane: the layer responsible for identity, platform logic, task orchestration, and realtime updates.
How the API fits in
Section titled “How the API fits in”The API sits at the center of Lombok’s runtime boundaries. As described in
Runtime Boundaries, the boundaries that
matter most when working in packages/api are:
- API ↔ browser. The main UI is a client of the backend, not the system of record. It reaches the API through authenticated HTTP/API calls and realtime Socket.io communication.
- API ↔ PostgreSQL. The backend stores platform/application state — users, folders, task records, app/platform configuration, metadata — in PostgreSQL through Drizzle ORM.
- API ↔ S3-compatible object storage. Platform state in PostgreSQL is kept distinct from file/object data in object storage.
- API ↔ worker runtime. The API decides what work should run; the worker runtime executes it. This is why app/runtime work is not treated as ordinary inline API logic.
- Task dispatch transport. Lombok’s documented mental model uses a DB-backed task table and Socket.io room-based dispatch between the API and the worker-side execution model — there is no assumed external Redis/BullMQ/RabbitMQ queue.
- Auth boundary. The architecture highlights JWT-backed auth flows across major communication paths.
Keep these boundaries in mind: changes in packages/api sit upstream of the
worker runtime’s execution and are the system of record the UI reads from.
Running the API locally
Section titled “Running the API locally”API development uses the same Docker-based local loop as the rest of the
repository, driven by the ./dx developer CLI. The full setup — prerequisites,
./dx up, PostgreSQL and MinIO, and the /etc/hosts entry — is documented in
Local Development with dx; this page
does not duplicate it.
To reload or restart just the API service:
./dx reload api./dx restart apiTo follow logs from the running environment:
./dx logsFor the full list of ./dx commands, run:
./dx helpDatabase and migrations
Section titled “Database and migrations”The API stores platform state in PostgreSQL through Drizzle (not Prisma).
The documented database workflow is driven through ./dx, for example:
./dx db migrateFor the broader database workflow and seeding, see Local Development with dx. A dedicated migrations page is planned for deeper workflow guidance.
API contract and SDK generation
Section titled “API contract and SDK generation”Lombok uses a shared contract model and OpenAPI-related tooling, with the
typed client surface in packages/sdk built around the platform API contract.
The documented generation commands are:
./dx generate openapi./dx generate metadataWhen you change the API surface, keep the shared contract and SDK in mind so consumers stay aligned. See the Core SDK page for how the typed client relates to the platform API.
Checks and tests
Section titled “Checks and tests”Use ./dx for the standard contributor checks. Linting, formatting, and
type-checking are shared across the monorepo:
./dx check all./dx check eslint./dx check prettier./dx check tscRun unit tests for the API package, and the API end-to-end suite, with:
./dx unit api./dx e2e apiRefer to Local Development with dx for how these commands fit into the wider workflow. Dedicated pages for tests and linting/type-checking are planned for this docs wave.
Core API work vs. app-level backend work
Section titled “Core API work vs. app-level backend work”These are two different surfaces, and it is worth being explicit about which one you are on:
- Working on the core API (this page) means changing Lombok’s control
plane — auth, storage, tasks, sockets, app-platform services, and the rest of
the responsibilities owned by
packages/api. - Building an app’s backend means writing the logic an app declares and ships, which runs on top of the platform as runtime workers rather than as inline API code.
If you are building app-level backend logic, the relevant docs are:
- App Architecture — how a manifest, triggers, tasks, workers, and contributions fit together
- Workers and Working on Workers — the runtime-worker execution model
- App Worker SDK — the code surface app backends use at execution time
- Events & Tasks — the orchestration model the API routes through
- App Database Access — app-level database support as a declared platform capability
The connecting idea: the API decides what work should run, and app backend logic is what runs through the worker runtime. Control-plane contributors work on the former; app authors work on the latter.
Contributor mental model
Section titled “Contributor mental model”When deciding where a backend change belongs:
- platform logic, auth, storage, tasks, sockets, or app-platform services →
packages/api - shared contracts and schemas crossing runtime boundaries →
packages/types - the typed client surface for API consumers →
packages/sdk - executing work once the API has dispatched it → the worker runtime in
packages/core-worker(see Working on Workers) - the backend logic an app declares and ships → the app-platform surface and
App Worker SDK, not
packages/api
Lombok is organized by runtime responsibility rather than by a single app folder, so matching your change to the right package keeps the boundaries clean.