Self-Host Budibase: Open Source Retool Alternative 2026
How to Self-Host Budibase: The Open Source Retool Alternative in 2026
TL;DR
Retool charges $10–$50/user/month for internal tools. Budibase is the open source alternative — a low-code platform for building data-backed apps, CRUD interfaces, and internal dashboards, self-hosted for the price of a VPS. It connects to PostgreSQL, MySQL, MongoDB, REST APIs, Airtable, S3, and more. Unlike Retool which runs in Retool's cloud by default, Budibase can run entirely on your infrastructure — your data never leaves your servers. The self-hosted community edition is free; the Business tier ($125/month for 25 users) adds advanced RBAC and SSO.
Key Takeaways
- Open source Retool alternative: drag-and-drop UI builder for internal tools, connected to your databases
- Self-hostable: Docker Compose or Kubernetes, data stays on your infra
- Data sources: PostgreSQL, MySQL, MSSQL, MongoDB, CouchDB, Oracle, Elasticsearch, Redis, S3, REST APIs, GraphQL, Google Sheets
- Automation: built-in workflow engine (cron, webhooks, database triggers)
- RBAC: role-based access control — not just read/write but per-table, per-row policies
- GitHub stars: 22,000+ (one of the most-starred internal tools projects)
- License: GPL v3 (community) / commercial (premium features)
Why Budibase Over AppSmith or ToolJet?
| Feature | Budibase | AppSmith | ToolJet |
|---|---|---|---|
| Built-in DB | CouchDB-based BudiBase DB | ❌ | PostgreSQL |
| Automation/Workflows | ✅ built-in | Limited | ✅ |
| Public apps | ✅ | ✅ | ✅ |
| Self-host difficulty | Easy | Easy | Easy |
| UI Components | ~50 | ~45 | ~45 |
| Best for | Full-stack internal apps | Data-heavy dashboards | Automation-heavy tools |
Budibase's differentiator is its built-in database (BudiBase DB, backed by CouchDB) — you can build full CRUD apps without connecting an external database. Combined with its automation engine, it's the most "complete" self-hosted option for building internal tools from scratch.
Self-Hosting with Docker Compose
Prerequisites
- Docker and Docker Compose
- 2GB RAM minimum (4GB recommended)
- Domain with DNS pointing to your server (for production)
docker-compose.yml
version: "3"
services:
minio-service:
container_name: budi-minio
image: minio/minio
volumes:
- minio_data:/data
environment:
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
command: server /data --console-address ":9001"
restart: unless-stopped
couch-init:
container_name: budibase-couchdb-init
image: ibmcom/couchdb3
environment:
COUCHDB_USER: ${COUCHDB_USER}
COUCHDB_PASSWORD: ${COUCHDB_PASSWORD}
command: curl -X PUT http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@couchdb-service:5984/_users
depends_on:
- couchdb-service
couchdb-service:
container_name: budibase-couchdb
image: budibase/couchdb
environment:
COUCHDB_USER: ${COUCHDB_USER}
COUCHDB_PASSWORD: ${COUCHDB_PASSWORD}
volumes:
- couchdb_data:/opt/couchdb/data
restart: unless-stopped
redis-service:
container_name: budibase-redis
image: redis
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
restart: unless-stopped
app-service:
container_name: budibase-app
image: budibase/apps:latest
environment:
SELF_HOSTED: 1
COUCH_DB_URL: http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@couchdb-service:5984
REDIS_URL: redis-service:6379
REDIS_PASSWORD: ${REDIS_PASSWORD}
MINIO_URL: http://minio-service:9000
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
JWT_SECRET: ${JWT_SECRET}
APP_PORT: 4002
WORKER_URL: http://worker-service:4003
BUDIBASE_ENVIRONMENT: PRODUCTION
depends_on:
- couchdb-service
- redis-service
- minio-service
restart: unless-stopped
worker-service:
container_name: budibase-worker
image: budibase/worker:latest
environment:
SELF_HOSTED: 1
PORT: 4003
REDIS_URL: redis-service:6379
REDIS_PASSWORD: ${REDIS_PASSWORD}
JWT_SECRET: ${JWT_SECRET}
COUCH_DB_URL: http://${COUCHDB_USER}:${COUCHDB_PASSWORD}@couchdb-service:5984
MINIO_URL: http://minio-service:9000
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
depends_on:
- redis-service
- minio-service
restart: unless-stopped
proxy-service:
container_name: budibase-nginx
image: budibase/proxy:latest
environment:
PROXY_RATE_LIMIT_WEBHOOKS_PER_SECOND: 10
PROXY_RATE_LIMIT_API_PER_SECOND: 20
depends_on:
- app-service
- worker-service
- minio-service
ports:
- "80:10000"
restart: unless-stopped
volumes:
couchdb_data:
minio_data:
redis_data:
.env file
# .env — copy and customize
COUCHDB_USER=admin
COUCHDB_PASSWORD=change-this-strong-password
REDIS_PASSWORD=change-this-redis-password
MINIO_ACCESS_KEY=change-this-minio-access
MINIO_SECRET_KEY=change-this-minio-secret
JWT_SECRET=change-this-jwt-secret-32-chars-min
Generate secrets:
openssl rand -hex 32 # Run 3x for each secret
Start and Configure
git clone https://github.com/Budibase/budibase.git
cd budibase/hosting
cp .env.example .env
# Edit .env with your secrets
docker compose up -d
# Check status
docker compose ps
# Access at http://localhost:80
On first launch, Budibase walks you through creating your admin account.
Connecting Data Sources
PostgreSQL Connection
1. Open your Budibase app
2. Click "Data" tab
3. "Add Source" → PostgreSQL
4. Fill in:
- Host: your-postgres-host.internal
- Port: 5432
- Database: mydb
- User: app_readonly (use a read-only user for safety)
- Password: ***
5. Click "Fetch Tables" — Budibase lists all tables
6. Click each table you want to use → "Fetch"
Budibase auto-generates a CRUD interface for each table. You can immediately build a data grid that reads, filters, sorts, creates, and deletes rows without writing any code.
REST API Connection
1. "Add Source" → REST API
2. Base URL: https://api.yourservice.com/v1
3. Headers:
- Authorization: Bearer {{API_KEY}}
(use Budibase's binding syntax {{}} to reference env variables)
4. Create queries:
- GET /users → List users
- POST /users → Create user
- GET /users/{{userId}} → Get user by ID
Building Your First App: An Admin Dashboard
Step 1: Set Up the Data
Connect your PostgreSQL users table. Budibase fetches the schema and creates default CRUD queries.
Step 2: Create Screens
New Screen → Table → Select "users" table
Budibase generates a full data grid with pagination, sorting, filtering, create/edit/delete forms. Customize the columns shown, add conditional formatting (red for status = 'suspended'), and add action buttons.
Step 3: Add Custom Automation
Create an automation that fires when a new user signs up:
Automation → Create
Trigger: Database row created (users table, condition: created_at > NOW() - INTERVAL 1 MINUTE)
Step 1: Send email (built-in SMTP)
To: admin@yourcompany.com
Subject: New user signed up
Body: {{trigger.row.email}} just registered
Step 2: Slack webhook
URL: {{env.SLACK_WEBHOOK_URL}}
Body: { "text": "New signup: {{trigger.row.email}}" }
Role-Based Access Control
Budibase has four built-in roles, customizable per-app:
| Role | Default Permissions |
|---|---|
| Admin | Full access |
| Power User | Create, edit, delete data |
| Basic User | Read + limited write |
| Public | Unauthenticated access |
Configure per-screen:
Screen Settings → Access → Set minimum role to "Power User"
For row-level security:
Data Source → users table → Row Access
Filter: id = {{ currentUser.id }}
# Users can only see their own rows
Custom Components and Plugins
Budibase supports custom components built in Svelte — for use cases the built-in component library doesn't cover:
# Initialize a new plugin
npx @budibase/cli@latest component init my-chart-component
cd my-chart-component
npm install
npm run build
# Upload to your Budibase instance
npx @budibase/cli@latest upload plugin
# → Enter your Budibase URL and API key
# Component appears in the UI builder immediately
The plugin system also supports data source plugins for connecting to custom APIs or databases not in Budibase's built-in list.
Automation: Scheduled Tasks and Webhooks
Budibase's automation engine replaces simple Zapier/n8n workflows for internal use cases:
Daily Report Email
Automation → Create
Name: Daily Active Users Report
Trigger: Schedule → Daily at 8:00 AM
Step 1: Query data
Data source: PostgreSQL
Query: SELECT COUNT(*) as daily_users FROM users
WHERE last_seen >= NOW() - INTERVAL 24 HOURS
Step 2: Send email
Provider: SMTP (configure in settings)
To: team@company.com
Subject: Daily Active Users — {{steps.1.rows[0].daily_users}} users yesterday
Body: |
Hi team,
Yesterday's active user count: {{steps.1.rows[0].daily_users}}
View the full dashboard: https://budibase.company.com/app/dashboard
Step 3: Post to Slack
Webhook URL: {{env.SLACK_WEBHOOK}}
Body: { "text": "📊 {{steps.1.rows[0].daily_users}} active users yesterday" }
Webhook Trigger (External Events)
Automation → Create
Trigger: Webhook
→ Copy the webhook URL: https://budibase.company.com/api/v1/automations/xxx/trigger
Step 1: Update database
Data source: PostgreSQL
Query: UPDATE orders SET status = '{{trigger.body.status}}'
WHERE id = '{{trigger.body.orderId}}'
Step 2: Send notification
...
Use the webhook URL in your payment processor, Stripe, or any external service to trigger Budibase automations on events.
Environment Variables and Secrets
Budibase has a built-in environment variable system for managing secrets across automations and queries:
Settings → Environment Variables
→ Add: STRIPE_API_KEY = sk_live_xxxx
→ Add: SLACK_WEBHOOK = https://hooks.slack.com/...
→ Add: INTERNAL_API_URL = https://api.company.internal
Reference them in queries and automations with {{env.STRIPE_API_KEY}}. Variables are encrypted at rest and never exposed to the frontend — they're server-side only.
Multi-App and Team Management
Budibase supports multiple apps per instance — organize by team or use case:
- Customer Support app: connected to your helpdesk database
- Finance app: connected to accounting PostgreSQL, restricted to finance team
- DevOps app: connected to Kubernetes API, restricted to engineers
- HR app: connected to HR system, restricted by department
Each app has independent RBAC, its own data sources, and separate publish/edit permissions. The admin panel shows all apps with their last modified date and access stats.
Scaling Budibase
The default Docker Compose setup is single-node. For higher availability:
# Scale app and worker services
docker compose up -d --scale app-service=3 --scale worker-service=2
For true HA, Budibase's enterprise documentation covers Kubernetes deployment with multiple replicas, shared CouchDB cluster, and Redis Sentinel. Most self-hosters don't need this — a single node handles hundreds of internal users comfortably.
Resource requirements by usage:
- 1-25 users: 2 vCPU, 4GB RAM ($12/month on Hetzner)
- 25-100 users: 4 vCPU, 8GB RAM ($25/month on Hetzner)
- 100+ users: Consider the cloud offering or HA setup
Production Hardening
TLS with Certbot
# Install certbot on the host
certbot certonly --standalone -d budibase.yourdomain.com
# Update nginx config in budibase/hosting/proxy/nginx.conf
# Or put a Caddy/Traefik proxy in front
Regular Backups
#!/bin/bash
# backup-budibase.sh
DATE=$(date +%Y%m%d_%H%M)
# CouchDB backup (all databases)
docker exec budibase-couchdb \
curl -X GET "http://admin:password@localhost:5984/_all_dbs" | \
jq -r '.[]' | while read db; do
curl -X GET "http://admin:password@localhost:5984/$db/_all_docs?include_docs=true" \
> /backups/budibase/couch_${db}_${DATE}.json
done
# MinIO backup (file attachments)
docker run --rm \
-v /backups/budibase/minio:/backup \
minio/mc mirror myminio/budibase /backup
echo "Budibase backup complete"
Upgrading Budibase
cd budibase/hosting
docker compose pull # Pull latest images
docker compose up -d # Restart with new images
docker compose logs -f # Watch for migration logs
Budibase runs database migrations automatically on startup. Major version upgrades may require following the migration guide in the changelog.
Cost Comparison: Retool vs Budibase Self-Hosted
| Plan | Retool | Budibase Self-Hosted |
|---|---|---|
| 5 users | $250/month | ~$10/month (VPS) |
| 25 users | $1,250/month | ~$20/month (VPS) |
| 50 users | $2,500/month | ~$30/month (VPS) |
| SSO/SAML | +$500/month | Business tier ($125/mo) |
| Audit logs | Enterprise | Business tier |
| Data location | Retool's cloud | Your server |
For a 10-person startup, switching from Retool to self-hosted Budibase saves roughly $1,000-$2,500/month — meaningful for early-stage teams. The trade-off is operational overhead: you're responsible for updates, backups, and uptime.
Methodology
- GitHub data from github.com/Budibase/budibase, March 2026
- Pricing data from budibase.com/pricing, March 2026
- Setup guide based on Budibase official documentation (docs.budibase.com)
- Version: Budibase 3.x (check GitHub releases for current version)
Why Self-Host Budibase?
The case for self-hosting Budibase comes down to three practical factors: data ownership, cost at scale, and operational control.
Data ownership is the fundamental argument. When you use a SaaS version of any tool, your data lives on someone else's infrastructure subject to their terms of service, their security practices, and their business continuity. If the vendor raises prices, gets acquired, changes API limits, or shuts down, you're left scrambling. Self-hosting Budibase means your data and configuration stay on infrastructure you control — whether that's a VPS, a bare metal server, or a home lab.
Cost at scale matters once you move beyond individual use. Most SaaS equivalents charge per user or per data volume. A self-hosted instance on a $10-20/month VPS typically costs less than per-user SaaS pricing for teams of five or more — and the cost doesn't scale linearly with usage. One well-configured server handles dozens of users for a flat monthly fee.
Operational control is the third factor. The Docker Compose configuration above exposes every setting that commercial equivalents often hide behind enterprise plans: custom networking, environment variables, storage backends, and authentication integrations. You decide when to update, how to configure backups, and what access controls to apply.
The honest tradeoff: you're responsible for updates, backups, and availability. For teams running any production workloads, this is familiar territory. For individuals, the learning curve is real but the tooling (Docker, Caddy, automated backups) is well-documented and widely supported.
Server Requirements and Sizing
Before deploying Budibase, assess your server capacity against expected workload.
Minimum viable setup: A 1 vCPU, 1GB RAM VPS with 20GB SSD is sufficient for personal use or small teams. Most consumer VPS providers — Hetzner, DigitalOcean, Linode, Vultr — offer machines in this range for $5-10/month. Hetzner offers excellent price-to-performance for European and US regions.
Recommended production setup: 2 vCPUs with 4GB RAM and 40GB SSD handles most medium deployments without resource contention. This gives Budibase headroom for background tasks, caching, and concurrent users while leaving capacity for other services on the same host.
Storage planning: The Docker volumes in this docker-compose.yml store all persistent Budibase data. Estimate your storage growth rate early — for data-intensive tools, budget for 3-5x your initial estimate. Hetzner Cloud and Vultr both support online volume resizing without stopping your instance.
Operating system: Any modern 64-bit Linux distribution works. Ubuntu 22.04 LTS and Debian 12 are the most commonly tested configurations. Ensure Docker Engine 24.0+ and Docker Compose v2 are installed — verify with docker --version and docker compose version. Avoid Docker Desktop on production Linux servers; it adds virtualization overhead and behaves differently from Docker Engine in ways that cause subtle networking issues.
Network: Only ports 80 and 443 need to be publicly accessible when running behind a reverse proxy. Internal service ports should be bound to localhost only. A minimal UFW firewall that blocks all inbound traffic except SSH, HTTP, and HTTPS is the single most effective security measure for a self-hosted server.
Backup and Disaster Recovery
Running Budibase without a tested backup strategy is an unacceptable availability risk. Docker volumes are not automatically backed up — if you delete a volume or the host fails, data is gone with no recovery path.
What to back up: The named Docker volumes containing Budibase's data (database files, user uploads, application state), your docker-compose.yml and any customized configuration files, and .env files containing secrets.
Backup approach: For simple setups, stop the container, archive the volume contents, then restart. For production environments where stopping causes disruption, use filesystem snapshots or database dump commands (PostgreSQL pg_dump, SQLite .backup, MySQL mysqldump) that produce consistent backups without downtime.
For a complete automated backup workflow that ships snapshots to S3-compatible object storage, see the Restic + Rclone backup guide. Restic handles deduplication and encryption; Rclone handles multi-destination uploads. The same setup works for any Docker volume.
Backup cadence: Daily backups to remote storage are a reasonable baseline for actively used tools. Use a 30-day retention window minimum — long enough to recover from mistakes discovered weeks later. For critical data, extend to 90 days and use a secondary destination.
Restore testing: A backup that has never been restored is a backup you cannot trust. Once a month, restore your Budibase backup to a separate Docker Compose stack on different ports and verify the data is intact. This catches silent backup failures, script errors, and volume permission issues before they matter in a real recovery.
Security Hardening
Self-hosting means you are responsible for Budibase's security posture. The Docker Compose setup provides a functional base; production deployments need additional hardening.
Always use a reverse proxy: Never expose Budibase's internal port directly to the internet. The docker-compose.yml binds to localhost; Caddy or Nginx provides HTTPS termination. Direct HTTP access transmits credentials in plaintext. A reverse proxy also centralizes TLS management, rate limiting, and access logging.
Strong credentials: Change default passwords immediately after first login. For secrets in docker-compose environment variables, generate random values with openssl rand -base64 32 rather than reusing existing passwords.
Firewall configuration:
ufw default deny incoming
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
Internal service ports (databases, admin panels, internal APIs) should only be reachable from localhost or the Docker network, never directly from the internet.
Network isolation: Docker Compose named networks keep Budibase's services isolated from other containers on the same host. Database containers should not share networks with containers that don't need direct database access.
VPN access for sensitive services: For internal-only tools, restricting access to a VPN adds a strong second layer. Headscale is an open source Tailscale control server that puts your self-hosted stack behind a WireGuard mesh, eliminating public internet exposure for internal tools.
Update discipline: Subscribe to Budibase's GitHub releases page to receive security advisory notifications. Schedule a monthly maintenance window to pull updated images. Running outdated container images is the most common cause of self-hosted service compromises.
Troubleshooting Common Issues
Container exits immediately or won't start
Check logs first — they almost always explain the failure:
docker compose logs -f budibase
Common causes: a missing required environment variable, a port already in use, or a volume permission error. Port conflicts appear as bind: address already in use. Find the conflicting process with ss -tlpn | grep PORT and either stop it or change Budibase's port mapping in docker-compose.yml.
Cannot reach the web interface
Work through this checklist:
- Confirm the container is running:
docker compose ps - Test locally on the server:
curl -I http://localhost:PORT - If local access works but external doesn't, check your firewall:
ufw status - If using a reverse proxy, verify it's running and the config is valid:
caddy validate --config /etc/caddy/Caddyfile
Permission errors on volume mounts
Some containers run as a non-root user. If the Docker volume is owned by root, the container process cannot write to it. Find the volume's host path with docker volume inspect VOLUME_NAME, check the tool's documentation for its expected UID, and apply correct ownership:
chown -R 1000:1000 /var/lib/docker/volumes/your_volume/_data
High resource usage over time
Memory or CPU growing continuously usually indicates unconfigured log rotation, an unbound cache, or accumulated data needing pruning. Check current usage with docker stats budibase. Add resource limits in docker-compose.yml to prevent one container from starving others. For ongoing visibility into resource trends, deploy Prometheus + Grafana or Netdata.
Data disappears after container restart
Data stored in the container's writable layer — rather than a named volume — is lost when the container is removed or recreated. This happens when the volume mount path in docker-compose.yml doesn't match where the application writes data. Verify mount paths against the tool's documentation and correct the mapping. Named volumes persist across container removal; only docker compose down -v deletes them.
Keeping Budibase Updated
Budibase follows a regular release cadence. Staying current matters for security patches and compatibility. The update process with Docker Compose is straightforward:
docker compose pull # Download updated images
docker compose up -d # Restart with new images
docker image prune -f # Remove old image layers (optional)
Read the changelog before major version updates. Some releases include database migrations or breaking configuration changes. For major version bumps, test in a staging environment first — run a copy of the service on different ports with the same volume data to validate the migration before touching production.
Version pinning: For stability, pin to a specific image tag in docker-compose.yml instead of latest. Update deliberately after reviewing the changelog. This trades automatic patch delivery for predictable behavior — the right call for business-critical services.
Post-update verification: After updating, confirm Budibase is functioning correctly. Most services expose a /health endpoint that returns HTTP 200 — curl it from the server or monitor it with your uptime tool.
Find more open source Retool alternatives on OSSAlt — self-hosting guides, community ratings, and feature comparisons.
Related: How to Migrate from Retool to Appsmith 2026 · Best Open Source Alternatives to Retool 2026 · Best Open Source Developer Tools in 2026