Skip to main content

Environment configuration

Basedash is configured with environment variables. With Docker Compose, set them in the environment template in the Distr portal (or your .env file). With Kubernetes, set the equivalent Helm values instead; run helm show values oci://registry.distr.sh/basedash/basedash-charts to list them.

Quick start: generate secrets

For Distr-managed deployments, store LICENSE_KEY, POSTGRES_PASSWORD, CRYPTO_KEY, and PRISMA_FIELD_ENCRYPTION_KEY as customer secrets in the Distr portal before the first deploy. The environment template reads them from there. Store CRYPTO_KEY and PRISMA_FIELD_ENCRYPTION_KEY somewhere safe. They encrypt data in the database, and changing them after you’ve saved data makes that data unreadable.

Required variables

Public URL: BASE_URL must be a full URL including http:// or https://. The app refuses to start with a bare hostname like basedash.example.com.
BASE_URL is used for login redirects, email links, OAuth and SSO callbacks, share links, and webhooks, so it must be the address your users actually open. License: The server won’t start without a valid key. Contact support@basedash.com if you don’t have one.
Database: For the bundled Compose PostgreSQL, set POSTGRES_PASSWORD. Compose derives DATABASE_URL from POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB, using host postgres (the service name), not localhost. Inside the app container, localhost is the app itself.
Encryption keys:
App image (manual Compose files only): Compose files downloaded from the Distr portal already pin the app image, so you don’t need this. If you use your own Compose file that reads APP_IMAGE, set it to a release, never latest:

Optional application settings

TLS and reverse proxy

HTTPS isn’t automatic. The app listens on port 3000 over plain HTTP. Direct access (default): open inbound TCP 3000 and use BASE_URL=http://<host>:3000. Reverse proxy (recommended for production): terminate TLS on 443 with your existing proxy or load balancer (nginx, Cloudflare, AWS ALB, Kubernetes ingress) and forward to port 3000. Then set:
Set TRUST_PROXY to the number of proxies in front of the app (usually 1; 2 for a load balancer in front of another proxy). This applies to Docker Compose; the Helm chart doesn’t expose it yet. Without it, Google sign-in redirects break and rate limiting sees every request as coming from the proxy. Don’t use TRUST_PROXY=true, because it lets any client forge its IP address. Cloudflare doesn’t proxy port 3000, so put Cloudflare in front of a proxy on 443, or connect to the server directly. Bundled Caddy: the Compose file includes an optional Caddy service for existing deployments that already use it. It’s off by default and the Distr agent doesn’t start it. For new deployments, use your own proxy.

PostgreSQL database

PostgreSQL is the only service Basedash depends on.

Bundled PostgreSQL

Docker Compose deployments (agent and manual) include a PostgreSQL 16 container:
  • Migrations run automatically every time the app starts
  • Health checks hold the app until the database is ready
  • Persistent storage in a Docker volume
The bundled database uses these variables:
Postgres only reads POSTGRES_PASSWORD the first time it initializes the data volume. Changing the variable later doesn’t change the database password. Reset it inside the container (ALTER USER basedash WITH PASSWORD '...') or recreate the volume.

External PostgreSQL

For production above 500 users, use a managed PostgreSQL instance (Amazon RDS, Cloud SQL, Azure Database for PostgreSQL). See Sizing.
  1. Use PostgreSQL 16 or later.
  2. Create the database:
  3. Set max_connections to at least 60 per app replica, plus 20.
  4. Point DATABASE_URL at it (with Helm, set postgres.enabled: false and postgres.external.url). This overrides the derived Compose URL:
    Percent-encode reserved URL characters in the password (+, /, =, @).
Migrations run automatically on first startup.

Database backups

Back up the database regularly, and always before upgrading. For managed databases, use your provider’s automated backups. For the bundled Compose database:

AI configuration

AI is optional on first boot. The app starts without a key and shows a banner until you add one. Chat, chart generation, and insights need a provider key. Supported providers: OpenAI, Anthropic, Azure OpenAI, Amazon Bedrock, xAI, and OpenRouter. Choose models with AI_MODEL (main agent) and AI_FAST_MODEL (lightweight tasks), using a provider prefix such as openai/ or anthropic/. If you leave them unset, Basedash picks defaults from the keys you’ve configured.

OpenAI

Anthropic

If you set both OpenAI and Anthropic keys, OpenAI models are the default.

Azure OpenAI

Point the OpenAI provider at your Azure OpenAI v1 endpoint. This supports every AI feature, including web search, chat attachments, and voice input.
Name each Azure deployment exactly like the model it serves: gpt-6.1-sol, gpt-6-luna, and gpt-transcribe for the defaults, or whatever you set in AI_MODEL and AI_FAST_MODEL. Existing deployments using AI_MODEL=azure/<deployment-name> with AI_AZURE_OPENAI_* variables keep working, but that setup doesn’t support web search, uploads, or voice input.

Amazon Bedrock

xAI

OpenRouter

OpenAI-compatible APIs

Any OpenAI-compatible endpoint (such as an internal LLM gateway) works through the OpenAI provider:

Model considerations

  • We test and benchmark against the default models. Other models may produce lower-quality SQL and charts.
  • Some features need specific model capabilities, such as tool calling and structured output.
  • Older variable names (OPENAI_API_KEY, OPENAI_MODEL, ANTHROPIC_API_KEY, AI_PROVIDER) still work, but the AI_* variables above take precedence.

Email configuration

Email delivers login codes, invitations, alerts, automation deliveries, and dashboard subscriptions.

First boot: log provider

The Distr templates set EMAIL_PROVIDER=log. Login codes are written to the app logs instead of being emailed, so you can sign in before email is set up. Switch to SMTP or SES before inviting users: anyone who can read the logs can read login codes.
Read codes with docker compose logs app (or kubectl logs on Kubernetes).

SMTP

Use port 587 with SMTP_SECURE=false (STARTTLS), or port 465 with SMTP_SECURE=true. Compose defaults SMTP_SECURE to true, so set it explicitly when you use port 587. Common SMTP providers:
  • Resend: smtp.resend.com:587
  • SendGrid: smtp.sendgrid.net:587
  • Mailgun: smtp.mailgun.org:587
  • AWS SES: email-smtp.us-east-1.amazonaws.com:587
  • Microsoft 365: smtp.office365.com:587

Amazon SES

Make sure your SES account is out of sandbox mode and SES_FROM_EMAIL is a verified identity.

Authentication and access control

Self-hosted Basedash has the same access controls as the cloud product:
  • SSO: SAML and OIDC with your identity provider. See SSO.
  • SCIM provisioning: provision and deactivate members and sync groups from Okta, Microsoft Entra ID, and other identity providers. Generate a SCIM token under Settings → Security.
  • Permissions: groups and per-dashboard, chart, and data source access.
  • Audit logs: available to Enterprise organizations.

License key

Self-hosted Basedash requires a license key from Basedash. Contact support@basedash.com to get one.

License behavior

At startup:
  • The server validates the key against https://charts.basedash.com before it accepts requests.
  • If the key is missing, invalid, expired, or inactive, or the license server can’t be reached, the server refuses to start.
While running:
  • The server sends a heartbeat every 6 hours with the app version and organization and user counts, for billing.
  • If a heartbeat fails, it retries with exponential backoff, starting at 5 minutes and capped at 6 hours.
  • If the license expires or is deactivated, an error banner appears and new organizations can’t be created.
  • If the license server can’t be reached, a warning banner appears and new organizations can’t be created until the next successful heartbeat. Existing users keep working.

Sandbox licenses

Sandbox licenses are for QA and CI environments. They show a “Sandbox environment” banner, and their usage isn’t billed.

Troubleshooting license issues

Server won’t start: check the app logs for the license error.
  • Missing key: set LICENSE_KEY and restart.
  • Can’t reach the license server: allow outbound HTTPS to charts.basedash.com (check firewalls, proxies, and egress rules).
  • Invalid, expired, or inactive: contact support@basedash.com.
“Unable to verify license” banner: the server couldn’t reach charts.basedash.com during a heartbeat. Check outbound HTTPS access. The server retries automatically. “License has expired” or “License has been deactivated” banner: contact support@basedash.com.

Update management

Basedash never updates your deployment automatically. You choose when to move to a new version:
  • Distr agent (Compose or Kubernetes): select a new version in the Distr portal.
  • Manual Compose: download the new version’s Compose file from the Distr portal, then run docker compose pull && docker compose up -d.
  • Manual Helm: set app.image.tag to the new release and run helm upgrade with the matching chart version.
Before upgrading, back up the database and read the release notes attached to each version in the Distr portal. Some releases include migrations that can’t be rolled back. For strict change control, upgrade a staging instance first.

Advanced configuration

Configure S3-compatible storage to enable:
  • Avatar and organization icon uploads
  • Chart images in Slack and email notifications and in the public API (without storage, images are rendered on demand and some notifications omit them)
  • CSV downloads generated by the AI
Works with AWS S3, Google Cloud Storage, DigitalOcean Spaces, MinIO, and other S3-compatible services. Uploaded images are served from https://{S3_BUCKET_NAME}.{endpoint host}. Bucket access:
  • Basedash marks avatars, icons, and chart images public-read itself. Don’t make the whole bucket public.
  • Keep the ai-csv-artifacts/ prefix private, including through any CDN. It holds query results.
  • Grant the credentials get, put, delete, and list access, plus multipart upload listing and abort.
  • Add a lifecycle rule on ai-csv-artifacts/ only that expires objects after 30 days and aborts incomplete multipart uploads after 1 day.
Follow these steps to use Google Cloud Storage (GCS) through its S3-compatible API.

Step 1: Create a bucket

  1. Go to the Google Cloud Console
  2. Navigate to Cloud Storage → Buckets
  3. Click Create bucket
  4. Configure the bucket:
    • Name: choose a globally unique name (e.g., basedash-uploads-yourcompany)
    • Location type: Regional is typically fine
    • Region: close to your Basedash deployment
    • Storage class: Standard
    • Access control: Fine-grained (required, because Basedash sets per-object ACLs)
    • Public access prevention: uncheck “Enforce public access prevention on this bucket”, so per-object public-read ACLs work
  5. Click Create
Don’t grant allUsers access on the bucket. That makes every object public, including AI-generated CSV files.

Step 2: Create HMAC keys

  1. Go to Cloud Storage → Settings
  2. Open the Interoperability tab
  3. Under “Access keys for service accounts,” click Create a key for a service account
  4. Select or create a service account with the Storage Object Admin role on the bucket
  5. Click Create key and save both values:
    • Access key: your S3_BUCKET_ACCESS_KEY_ID
    • Secret: your S3_BUCKET_SECRET_ACCESS_KEY

Step 3: Configure CORS

Browsers upload files directly with pre-signed URLs, so the bucket needs a CORS rule for your Basedash URL. Create cors.json:
Apply it:

Step 4: Set environment variables

Step 5: Verify

  1. Upload a user avatar or organization icon
  2. Check that the file appears in your bucket
  3. Open the file’s public URL directly

Slack app (optional)

Enable Slack notifications, automations, and chatting with Basedash from Slack. Set all five values:

Support and troubleshooting

Getting help

Health checks

On Kubernetes, use kubectl logs -l app.kubernetes.io/component=app.

Common configuration issues

Application won’t start:
  1. Check that all required variables are set: LICENSE_KEY, CRYPTO_KEY, PRISMA_FIELD_ENCRYPTION_KEY, POSTGRES_PASSWORD, and BASE_URL
  2. With bundled PostgreSQL, leave DATABASE_URL derived (host postgres, not localhost). Override it only for an external database
  3. Make sure BASE_URL includes http:// or https://
  4. Make sure CRYPTO_KEY is exactly 32 bytes (openssl rand -hex 16)
  5. Make sure the server can reach charts.basedash.com over HTTPS
  6. Read the logs: docker compose logs app
Postgres password authentication failed after changing env: Postgres only applies POSTGRES_PASSWORD when the data volume is first created. Reset it inside the container (ALTER USER basedash WITH PASSWORD '...') so it matches POSTGRES_PASSWORD, or recreate the volume (this deletes all data). If you overrode DATABASE_URL, its password must match too. Browser never loads, but Distr shows healthy: Distr’s health check calls /health inside the container, so it can pass while the app is unreachable from outside. Check:
  1. curl http://127.0.0.1:3000/health on the host
  2. Inbound TCP 3000 is open in your security group or firewall
  3. You’re using http://<host>:3000, not https://
  4. If the hostname is on Cloudflare, port 3000 isn’t proxied. Try the server IP, or turn off proxying for the record
“Something went wrong” on first page load: Expand the error message on that screen or check the app logs. The usual cause is a BASE_URL without http:// or https://. Google sign-in redirects to http:// or fails behind a proxy: With Docker Compose, set TRUST_PROXY to the number of proxies in front of the app (usually 1). AI features not working:
  1. Set a provider key (for example AI_OPENAI_API_KEY) and, if you override models, a matching provider-prefixed AI_MODEL
  2. Check the provider account’s credits and rate limits
  3. Check that the server can reach the provider’s API endpoint
Email not arriving:
  1. If EMAIL_PROVIDER=log, codes are in the app logs, not in email
  2. For SMTP, check the host, port, and credentials
  3. Match SMTP_SECURE to the port: false for 587, true for 465
  4. Make sure the firewall allows outbound SMTP
Connecting a database shows “Database connection not found”: CRYPTO_KEY must be exactly 32 bytes. Generate one with openssl rand -hex 16, restart the app, and connect again. You can safely replace the key only if no database connection has been saved yet.