Skip to content

Multi-tenant sites

By default every conversation goes into the one project set by nebulasProjectId. If one deployment serves several customers (tenants), you probably want each tenant’s conversations in their own project.

nebulasProjectMode: "name-from-metadata" does this. It reads a project_name from each caller’s service-account metadata, finds the project with that name in Nebulas, and creates it the first time.

src/lib/nebulas.ts
configureNebulasServer({
nebulasApiUrl: process.env.NEBULAS_API_URL, // needed for the lookup and creation
nebulasAuthStrategy: "service_account",
serviceAccount: {
serviceAccountId: process.env.SERVICE_ACCOUNT_ID ?? "",
keyId: process.env.SERVICE_ACCOUNT_KEY_ID ?? "",
privateKeyPath: process.env.SERVICE_ACCOUNT_PRIVATE_KEY_PATH,
// Your endpoint. It returns the caller's claims, e.g.
// { "org_id": "...", "project_name": "acme-support" }
metadataUrl: process.env.SERVICE_METADATA_URL,
},
nebulasProjectMode: "name-from-metadata",
});

metadataUrl is called with the caller’s session token (bearerToken or getSessionToken), so each caller gets their own claims. Results are cached briefly per caller.

  • Service-account auth only. The project search and creation run as your app, never as a visitor. With any other strategy, keep the mode unique.
  • Leave serviceAccount.metadata unset. If it’s set, it’s used instead of metadataUrl everywhere, and every caller ends up in the same project.
  • Names are matched exactly (case-insensitive): support never matches support-legacy.
  • Results are cached for about 10 minutes per org and name. Simultaneous first requests share one lookup, so the project is never created twice.

resolveNebulasProjectId() is exported if you need to resolve the project somewhere other than the config endpoint.