Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Organize sites into a project

A project is boatramp’s owning + tenant boundary. It groups many sites together with their functions and compute, and it is the tenant a managed handler’s row-level scope resolves to. Every resource belongs to exactly one project; a reserved default project holds everything that predates projects, so if you never name a project you keep the single-site experience unchanged.

Use projects when you run more than one site per operator (agencies, monorepos, multi-tenant SaaS) and want each tenant’s sites, functions, and compute isolated — including their names. Two projects can each own a site called blog.

Before you start

1. Create a project

boatramp project create acme --display "Acme, Inc."
boatramp project ls

create needs a slug (unique, no /); --display, --description, and --region are optional. project ls lists every project; project show acme prints the full record; project rm acme deletes an empty project. It refuses while the project still owns resources — and the refusal now enumerates exactly what remains, grouped by resource family — so you know what to delete first. The default project can never be removed.

To tear a project down wholesale, project rm acme --force cascades: it deprovisions the project’s managed databases, removes its compute workloads and their volumes, deletes its functions and sites (releasing the sites’ global domain claims), clears its secrets and GraphQL safelist, then removes the project. Preview it first with --dry-run (prints exactly what would be destroyed, changes nothing); a bare --force shows that same plan and asks you to type the project name to confirm, so add --yes to skip the prompt (required when stdin isn’t a terminal):

boatramp project rm acme --dry-run     # what would be destroyed
boatramp project rm acme --force       # cascade, with a typed-name confirmation
boatramp project rm acme --force --yes # cascade, unattended

2. Target a project

Every site-scoped command takes a --project flag; it falls back to [publish].project in project.cfg, then the BOATRAMP_PROJECT environment variable, then the default project. So these are equivalent:

boatramp --project acme sync ./dist --site blog
BOATRAMP_PROJECT=acme boatramp sync ./dist --site blog

With --project omitted you are working in default, byte-identical to how boatramp behaved before projects existed. A site name only has to be unique within its project, so acme/blog and beta/blog are two different sites that deploy, serve, and run their background work independently.

3. Declare a whole project at once

boatramp apply reconciles an entire project from one manifest — see Declare a project with apply. A minimal apply.cfg:

(
    project: "acme",
    sites: [
        ( name: "www",  path: "www/dist" ),
        ( name: "blog", path: "blog/dist", routing: ( clean_urls: true ) ),
    ],
)
boatramp apply -f apply.cfg

What a project owns

  • Sites — each with its own deployments, aliases, domains, and background work (consumers, crons). Same-named sites in different projects are fully isolated.
  • Functions — top-level functions and their versions, triggers, invocations, and metering.
  • Compute — container / micro-VM workloads.
  • A tenant identity — a request routed to one of the project’s sites carries the project as its host-asserted tenant, which is what a managed handler’s Authorized::db() scopes rows to (nothing guest-supplied).

Content-addressed bodies (blobs, manifests, site and compute config) are shared across projects and deduplicated — a byte-identical asset uploaded by two projects is stored once, and it is only garbage-collected when no project references it.

Authorization

Cedar gains a Project resource with three project-scoped roles — project_admin, project_publisher, project_viewer — that govern a project’s sites, functions, compute, and workflows. A token scoped to one project cannot touch another: a project_admin:acme token is refused (403) on project beta. Legacy site-only grants (publisher:blog) read as publisher:default/blog, so existing tokens keep working against the default project. See RBAC roles, actions & resources.

See also