Budibase: Low-Code Platform That Actually Connects to My Existing Database
Our ops team was managing 200+ SKUs across three Google Sheets, a legacy Access database, and a MySQL inventory system. They needed a unified interface but the IT team had a 6-month backlog. I set up Budibase self-hosted, connected it to all three data sources, and built a working inventory management app in 4 hours. The ops team had something usable by end of day. Here's how it works and the issues I hit.
Self-Hosting That Actually Works
# Self-host Budibase with Docker Compose
git clone https://github.com/Budibase/budibase.git
cd budibase
docker compose up -d
# Or use the official Docker image directly
docker run -d \
--name budibase \
-p 10000:80 \
-v budibase_data:/data \
budibase/budibase:latest
# Access: http://localhost:10000
# Create admin account on first visit
Self-hosting matters because Budibase cloud has per-user pricing that gets expensive at scale. With 20+ internal users, the self-hosted version saves significant cost and keeps data on your own infrastructure.
Connecting to External Databases
Budibase connects to external databases as data sources. Your data stays in your database — Budibase reads and writes directly:
# Supported data sources:
# - PostgreSQL
# - MySQL
# - SQL Server
# - MongoDB
# - REST API
# - Google Sheets
# - S3 / Airtable / Snowflake
# In the Budibase UI:
# 1. Go to Data → Create Data Source
# 2. Select "PostgreSQL"
# 3. Enter connection details:
# Host: db.example.com
# Port: 5432
# Database: inventory
# User: budibase_readwrite
# Password: ****
# 4. Budibase scans the schema and lists all tables
# 5. Select which tables to expose as "queries"
# 6. Each table becomes available in the app builder
Problem
Connected Budibase to a MySQL database with a 500K row orders table. Loading the list view took 30+ seconds. The connector was fetching all rows without LIMIT, and the join to the customers table multiplied the result set.
What I Tried
Tried setting a row limit in the Budibase query configuration. That helped but then users couldn't search beyond the first 1000 rows. Tried creating a database view with the join pre-computed — that worked but required DBA involvement.
Actual Fix
Use custom SQL queries instead of auto-generated ones. Budibase lets you write raw SQL with parameters:
-- Budibase custom query: search_orders
SELECT
o.id,
o.order_date,
o.total,
o.status,
c.name AS customer_name
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
WHERE
(:search = '' OR c.name LIKE CONCAT('%', :search, '%'))
AND (:status = '' OR o.status = :status)
ORDER BY o.order_date DESC
LIMIT 50 OFFSET :offset
-- Parameters:
-- :search (string, default: "")
-- :status (string, default: "")
-- :offset (number, default: 0)
Building a CRUD App in 15 Minutes
The app builder is drag-and-drop. Here's the workflow for a typical internal tool:
- Create data source — connect to MySQL/PostgreSQL
- Auto-generate screens — Budibase creates list, create, edit, and detail views automatically
- Customize the layout — drag and drop components, change column order, add filters
- Add automation — "when status changes to 'shipped', send email"
- Set permissions — define who can see/edit what
- Publish — the app is live at a URL, accessible to your team
Automation Workflows
Budibase automations are the equivalent of Zapier but self-hosted and free. Here's what I set up for inventory management:
// Automation: Low stock alert
// Trigger: "On row update" in "inventory" table
// Condition: stock < reorder_level
// Step 1: Query the suppliers table for this product
const supplier = await fetchSupplier(record.product_id)
// Step 2: Send email to purchasing team
await sendEmail({
to: "purchasing@company.com",
subject: `Low stock: ${record.product_name}`,
body: `${record.product_name} is at ${record.stock} units.
Reorder level: ${record.reorder_level}
Supplier: ${supplier.name} (${supplier.email})`
})
// Step 3: Create a task in the "reorder_tasks" table
await createRecord("reorder_tasks", {
product_id: record.product_id,
current_stock: record.stock,
reorder_qty: record.reorder_qty,
status: "pending",
assigned_to: "purchasing_team"
})
// This automation runs automatically whenever inventory is updated
Problem
Configured Google OAuth for SSO. The login button appeared, users clicked it, authenticated with Google, but got redirected back to Budibase without being logged in. No error message.
What I Tried
Tried different redirect URLs. Checked the Google Cloud Console — the OAuth consent screen was configured. Tried using the user's Google email as their Budibase username.
Actual Fix
The issue was the redirect URI. For self-hosted Budibase behind a reverse proxy, the redirect URI needs to match exactly — including http vs https:
# In Google Cloud Console → OAuth 2.0 Client:
# Authorized redirect URIs must match EXACTLY
# For self-hosted behind nginx:
https://budibase.yourdomain.com/api/global/auth/_google/callback
# Common mistake: using http:// instead of https://
# when behind a reverse proxy that terminates SSL
# Also set in Budibase environment variables:
BB_GOOGLE_CLIENT_ID=your-client-id
BB_GOOGLE_CLIENT_SECRET=your-client-secret
BB_GOOGLE_REDIRECT_URL=https://budibase.yourdomain.com/api/global/auth/_google/callback
# The BB_GOOGLE_REDIRECT_URL must match the Google Console exactly
SSO with Google/Azure
Budibase supports multiple SSO providers out of the box:
- Google Workspace — users sign in with their Google account
- Azure AD / Microsoft Entra ID — for enterprise environments
- OIDC — any OIDC-compatible identity provider
- LDAP — for legacy enterprise setups
After SSO is configured, users don't need separate Budibase accounts. Their Google/Azure identity maps to Budibase roles automatically.
What I Learned
- Budibase is fast for standard internal tools. CRUD apps, dashboards, forms — build in hours, not weeks.
- Use custom SQL queries for complex data. The auto-generated queries work for simple tables but struggle with joins and large datasets.
- Automations replace manual processes. The ops team stopped using email chains for reorder requests. The automation handles it.
- Self-hosting saves money but needs maintenance. Budget time for updates and backup.
- SSO configuration needs attention to detail. Redirect URIs must match exactly. Test thoroughly before rolling out.
Wrapping Up
Budibase replaced three separate tools (Google Sheets, Access, and a custom PHP app) with one unified interface. The ops team can now manage inventory from a single dashboard, the automation handles reorder alerts, and SSO means everyone logs in with their existing Google accounts. For teams that need internal tools without waiting months for developer time, Budibase is the answer.