Deploy spec & headers

How AxHub builds your app and how it gives you the logged-in user — the two things a developer needs to know.


If you're editing the app's code, two things matter — how AxHub builds your code (the deploy spec) and how it gives you the logged-in user (SSO headers). Template apps already have both set up; this is what to know when you bring your own code.

Deploy spec — how AxHub picks the build

AxHub looks at your repo files and picks a build method in this order. It stops at the first match.

  1. axhub.yaml — if present, this manifest wins
  2. Dockerfile — at the root, builds a single image
  3. Compose filedocker-compose.yml · docker-compose.yaml · compose.yaml · compose.yml
  4. Railpack auto-detection — otherwise, infers the framework from marker files (package.json→node, go.mod→go, requirements.txt/pyproject.toml→python, Cargo.toml→rust, etc.)

If none of the four exist, there's nothing to build and it fails.

Add an axhub.yaml when the build/start command is ambiguous or you want to pin it.

axhub.yaml
version: axhub/v1
runtime:
  port: 3000
  health_path: /
build:
  deploy_method: docker
  dockerfile: Dockerfile
env:
  required:
    - name: DATABASE_URL
      scope: runtime

axhub.yaml is the current name that replaces the old apphub.yaml. If both exist, axhub.yaml wins. The full schema is in the axhub.yaml reference.

SSO headers — read the logged-in user

An app behind AxHub doesn't need its own login. The gate handles auth and adds six user-info headers to requests that pass.

HeaderValue
X-AxHub-User-IDUser UUID
X-AxHub-User-EmailBase64-encoded email
X-AxHub-User-NameBase64-encoded name
X-AxHub-App-Roleowner · platform_admin · tenant_admin · app_member · tenant_member
X-AxHub-Is-Admintrue · false
X-AxHub-Tenant-SlugTenant slug

Read them on the server:

export function currentAxHubUser(req: Request) {
  const h = req.headers;
  return {
    id: h.get('x-axhub-user-id'),
    email: Buffer.from(h.get('x-axhub-user-email') ?? '', 'base64').toString('utf8'),
    name: Buffer.from(h.get('x-axhub-user-name') ?? '', 'base64').toString('utf8'),
    role: h.get('x-axhub-app-role'),
    isAdmin: h.get('x-axhub-is-admin') === 'true',
    tenant: h.get('x-axhub-tenant-slug'),
  };
}

Always read these on the server. The gate overwrites any X-AxHub-* the client sends — and when access is denied, all six headers arrive empty. So if X-AxHub-User-ID is empty, treat the request as unauthenticated.

Redeploy on change

Push a new commit to the connected repo and a deploy starts again. You can also create a deployment manually from the Deploy tab in the web console.