User Connections (Server Storage)
Save personal ClickHouse connections to the server so they sync across devices when signed in with Clerk — encrypted at rest with AES-256-GCM.
Save personal ClickHouse hosts to the server so they sync across devices when signed in with Clerk — encrypted at rest with AES-256-GCM.
Prop
Type
What it does
When enabled, users can choose Save to server in the Add Host dialog. Credentials are encrypted at rest with CHM_USER_CONNECTIONS_ENCRYPTION_KEY and never returned to the client after save.
Browser-only storage remains available when server storage is disabled or the user prefers a local connection.
Using it
Server storage needs four things present together. If any one is missing the server returns "User connections database storage is not enabled" and the Save to server toggle stays hidden.
CHM_FEATURE_USER_CONNECTIONS_DB=true— the feature flag.- Clerk auth (
CHM_AUTH_PROVIDER=clerk) — connections are keyed by the signed-in ClerkuserId. CHM_USER_CONNECTIONS_ENCRYPTION_KEY— a 32-byte base64 key used to encrypt credentials at rest (AES-256-GCM).- A database backend —
CHM_CLOUD_D1on Cloudflare, orDATABASE_URL/POSTGRES_URLon Docker / Kubernetes.
One canonical name
Set the canonical CHM_* name once. The browser-side VITE_FEATURE_USER_CONNECTIONS_DB / VITE_AUTH_PROVIDER are derived from CHM_FEATURE_USER_CONNECTIONS_DB / CHM_AUTH_PROVIDER at build time (see vite.config.ts) — you don't set them separately. Because the client value is inlined at build time, set these before pnpm run build (or build a custom image), then keep them in the runtime env too.
Enable the feature and Clerk auth
CHM_FEATURE_USER_CONNECTIONS_DB=true
CHM_AUTH_PROVIDER=clerkConfigure a database backend
Use the CHM_CLOUD_D1 binding (shared D1 database; migration 0002_user_connections.sql).
Set DATABASE_URL or POSTGRES_URL.
Set the encryption key
32-byte key, base64-encoded (a secret — never commit it):
wrangler secret put CHM_USER_CONNECTIONS_ENCRYPTION_KEY
# Docker / Kubernetes: pass CHM_USER_CONNECTIONS_ENCRYPTION_KEY via -e or a SecretRedeploy the dashboard
The Add Host dialog shows an enabled Save to server toggle when all four requirements are met. Otherwise it displays a note with a link to this page.
Permissions & access
Per-user isolation
Each connection row is keyed by the signed-in Clerk userId. List, read, update, delete, and chart/table proxy routes all resolve auth first and query with WHERE user_id = ?. Guessing another user's connectionId returns 404 — never their credentials.
- Not org-shared: Connections belong to the individual Clerk account, not the whole organization. Two teammates each see only their own server-stored hosts.
- Passwords are encrypted with AES-256-GCM before writing to D1/Postgres.
- API routes return connection metadata only; passwords are never echoed after create.
- Browser-stored hosts use short-lived session tokens so passwords are not sent on every chart/table request.
- The client cache for server connections is scoped per Clerk user, cleared on sign-out / account switch, and excluded from persisted localStorage so another login on the same browser cannot flash a prior user's host list.
- Shared
?host=-1000URLs only work for the same signed-in user with that connection saved.