Multiple backends
Use multiple backends when one Layeron project has separate app areas that are easier to maintain in separate entry files.
import { project } from "@layeron/core"
export default project({ backends: { api: "./src/api.ts", admin: "./src/admin.ts", jobs: "./src/jobs.ts", },})Each backend entry default-exports a backend(...) app:
import { backend } from "@layeron/core"import { db, storage } from "@layeron/modules"
const database = db({ name: "main" })const files = storage.bucket({ name: "uploads" })
const app = backend({ project: "billing", name: "api", compatibilityDate: "2026-05-24",})
app.use(database)app.use(files)app.get("/api/health", () => ({ ok: true }))
export default appimport { backend } from "@layeron/core"import { db } from "@layeron/modules"
const database = db({ name: "main" })
const app = backend({ project: "billing", name: "admin", compatibilityDate: "2026-05-24",})
app.use(database)app.get("/admin/health", () => ({ ok: true }))
export default appCompile model
Section titled “Compile model”All backend entries in one project({ backends }) compile into one AppSpec,
RuntimeTopology, resource graph, deployment plan, and deployment state for the
selected environment.
Layeron records the backend id in declaration metadata so compiled records, diagnostics, logs, and dashboard views can point back to the entry that declared them.
Backend entries with the same public runtime fields share one generated app Worker. Backend entries with different public runtime fields get separate app Workers automatically.
Public runtime fields are:
endpointgatewayplacementobservability
Each generated app Worker receives the routes, custom domain, gateway policy, compute placement, and Worker observability settings for its backend group.
Shared resources
Section titled “Shared resources”Equal module declarations share the same logical resource.
const database = db({ name: "main" })const files = storage.bucket({ name: "uploads" })If two backend entries declare the same module with the same configuration, Layeron lowers that module once. The backend entries can use the shared module from their own routes and handlers.
Use different namespace or name values when app areas need separate
resources:
const adminDatabase = db({ namespace: "admin", name: "main",})Project fields
Section titled “Project fields”Every backend entry must use the same backend({ project }) slug. The project
slug is the deployment and resource naming boundary.
These fields may differ per backend entry:
endpointgatewayplacementobservability
Layeron stores per-backend values in AppSpec.metadata.backends[]. When every
backend entry uses the same value, Layeron also keeps the shared value at the
top level for compatibility with single-backend tooling.
These fields must match across backend entries when they are present:
compatibilityDatecompatibilityFlags
Use project({ env }) in layeron.config.ts for non-secret environment values
that should apply to the whole compiled project.
When to split
Section titled “When to split”Split backends when code ownership, routing, or deployment review is clearer with separate files:
- public API routes
- admin routes
- queue or job handlers
- webhook handlers
- app-area-specific modules
Keep one backend entry when the app is small or the split would only move a few routes without making ownership clearer.