What changes relative to Hybrid
The data planes are the same binaries. What is added is everything that was previously operated for you.
The token columns are the part people find surprising. In external mode there is no SaaS to authenticate to, so the two credentials that dominate a hybrid install simply do not exist. What replaces them is a set of internal JWT secrets that must match on both sides of every call — and the chart generates and aligns all of them.
DataCore instead of DataAgent
In hybrid, DataAgent answers queries pushed from SaaS over an outbound stream. External mode has no SaaS, so that role disappears and DataCore takes over: an in-cluster HTTP API that serves tenant-scoped queries directly from ClickHouse, plus deployment metadata from its owndatacore PostgreSQL database.
The console reaches it at DATACORE_URL with a JWT signed by a secret that must equal DataCore’s AUTH_JWT_HS256_SECRET. The chart wires both ends from a single generated value. If you override one by hand you must override the other, or every dashboard returns an authorization error.
Step 1: prepare the datastores
External mode needs three, and unlike hybrid, ClickHouse is mandatory.
That split is deliberate. Postgres and Redis are almost always managed services in production, so the usual external values file sets
deploy: false for both and names the endpoints once on global.postgresql / global.redis (per-service hosts inherit since chart 2.6.0). ClickHouse is the opposite: nearly everyone runs the in-cluster subchart, because it is telemetry storage the platform owns end to end. Connecting an external ClickHouse is supported but rare — treat it as the exception, not the starting point.
For managed Postgres, keep runtime role passwords in a Secret you create and reference with per-service existingSecret hooks — see
External per-service datastore credentials.
Since chart 2.8.0 the control-plane neuraltrust password goes the same way, through global.postgresql.passwordSecret, so an external values file can hold no credential at all; before that it had to be readable at render time as global.postgresql.password, because the chart composed the console’s connection string while rendering. Replacing postgresql-secrets wholesale with global.postgresql.existingSecret is a different contract (Hybrid / full Secret takeover) and is usually the worse path for External.
On AWS you can use RDS IAM authentication. Set global.postgresql.authMode: iam. Be aware of a current gap: that umbrella setting does not reach the Go gateways in external mode, so also set agentgateway.database.iamAuth: true and trustguard.database.iamAuth: true. Without them the gateways attempt password authentication against an IAM-only database and fail at connection time with nothing pointing at the cause.
Step 2: decide the console hostname first
APP_URL and NEXTAUTH_URL drive email links, SSO redirects, and OAuth callbacks. Changing them later invalidates in-flight invitations and breaks configured SSO redirect URIs, so pick the hostname before installing.
One limitation to be aware of: a handful of console values are NEXT_PUBLIC_*, which Next.js inlines into the JavaScript bundle at image build time. They cannot be set by Helm. In practice only two matter, and both are cosmetic-to-annoying rather than blocking — the SCIM tenant URL shown to administrators and the meta.location returned to your IdP will show app.neuraltrust.ai. Enter your own host in your IdP rather than copying what the screen displays.
Step 3: the bootstrap admin
There is no sign-up flow, and the database seed creates no users — it seeds the evaluator catalog and reference data only. The first administrator comes from two environment values:DEPLOYMENT_MODE=external and both the email and password are non-empty. On password login the console checks these before normal user authentication, and on a match upserts the user with a verified email and grants OWNER on every team.
Treat it as a break-glass account: it bypasses the normal user table by design. Create a personal administrator through the UI afterwards.
Step 4: install, and watch the ordering
Two things must complete before the console serves traffic:- A pre-install Helm hook Job generates the MCP OAuth RSA signing key into a Secret. It checks for an existing key first, so upgrades do not rotate it and invalidate live access tokens. It only ever writes its own Secret — the Role is name-scoped.
- An init container runs
prisma migrate deployfollowed by the seed.
maxUnavailable: 0, so a failed migration blocks the rollout rather than serving against a half-migrated schema. Note that control-plane-api reads the same schema and runs no migrations of its own — it assumes the console has already applied them.
Step 5: configuration comes from Postgres, not config sync
This is the step most likely to trip you up if you have deployed hybrid before. In hybrid, a data plane holds no database connection for its own configuration and pulls snapshots from SaaS over gRPC. External mode inverts that. Config sync is off by default, and each product’s data plane reads its configuration directly from that product’s PostgreSQL database, which its own in-cluster control plane owns and migrates. Practical consequences:- There is no config-sync token to create and no snapshot cache to reason about
- Data-plane readiness has no snapshot gate, so
RunningandReadytrack each other closely - Each product needs its own database and role, not one shared credential —
agentgateway,trustguard,datacore, plus the platform database
kubernetes.io/tls Secret including ca.crt through configSync.grpcTls.existingSecret; setting autoGenerate: false without one is rejected at render time.
Step 6: verify
What you have taken on
Worth stating plainly, since it is the real cost of external mode:- Database migrations are yours to run and to roll back
- Backups of PostgreSQL and ClickHouse are yours
- Certificate rotation for anything you supplied yourself
- The bootstrap credential is a standing break-glass path into every team
- Email deliverability — invitations and password resets stop working silently if it breaks
Known rough edges
External mode is newer than Hybrid, and these are the issues you are most likely to meet. Each has a workaround in Troubleshooting.- Login lockout after repeated failed password attempts
- SCIM setup screens display the SaaS host instead of yours
- Alert evaluation does not currently run
- Firewall complexity state silently disables itself without a Redis URL
- Trace export returns 404 when the OTLP endpoint includes a signal path
imagePullSecretsis only honoured on the console undercontrol-plane-app- IAM database auth needs setting per gateway, not only globally