Bubble cannot open a TCP connection to SQL Server's port 1433 — all database calls must go through HTTPS. The recommended pattern is an Azure Function using the mssql Node.js library as a REST layer, with the SQL Server connection string stored in Azure Application Settings. If you have an existing ASP.NET or Azure API Management endpoint in front of your SQL Server, point Bubble's API Connector directly at that.
| Fact | Value |
|---|---|
| Tool | Microsoft SQL Server |
| Category | Database & Backend |
| Method | Bubble API Connector |
| Difficulty | Advanced |
| Time required | 2–4 hours |
| Last updated | July 2026 |
Bubble + SQL Server: Start with the Question 'Does a REST API Already Exist?'
Microsoft SQL Server integrations with Bubble are distinct from MySQL and PostgreSQL integrations in one important way: the audience. Founders looking to connect Bubble to SQL Server are almost always working with enterprise systems — Dynamics 365 data, a legacy .NET ERP, SharePoint lists backed by SQL Server, or a custom business application built by an internal dev team. In these environments, there is a high probability that a REST API already exists in front of the SQL Server database.
ASP.NET Web API, Azure API Management, OData v4 endpoints, and custom REST controllers built on Entity Framework are extremely common in .NET enterprise stacks. If your company's dev team built the SQL Server application, ask them whether a REST or OData API is already exposed — this is the single fastest path to a working Bubble integration. You simply point Bubble's API Connector at the existing endpoint with whatever auth mechanism it uses (Bearer token, API key, Azure AD OAuth).
When no existing REST API exists, the cleanest new-build option is an Azure Function. Azure Functions natively integrate with SQL Server (especially Azure SQL), support both SQL Server Authentication and Managed Identity (for Azure-hosted SQL Server), and store connection strings in Application Settings that are encrypted at rest and never visible in Bubble. The `mssql` npm package in a Function handles the TDS protocol, prepared statements, and connection pooling — the Function itself just exposes clean HTTPS endpoints for Bubble to call.
A crucial SQL Server-specific pattern is stored procedures. Enterprise SQL Server databases almost always have complex business logic encoded in T-SQL stored procedures — audit logging, multi-table transactions, computed fields, and access control rules. Rather than exposing raw table queries through your REST layer, call stored procedures (`EXEC sp_GetOrderDetails @orderId = ?`) and return the result set. This keeps T-SQL business logic in the database where it belongs, gives DBAs control over what data Bubble can access, and means Bubble never needs to know the underlying table structure.
Another consideration unique to SQL Server on Azure: Azure SQL's Serverless tier auto-pauses the database after a configurable period of inactivity (default 1 hour). The first request after a pause triggers a cold start that can take 15–30 seconds to respond. For Bubble apps serving real users, disable auto-pause for the production database or increase the minimum pause delay significantly. Development and staging databases can use auto-pause to save costs.
Integration method
Bubble API Connector calls an Azure Function (using the mssql npm package) or an existing ASP.NET/.NET Web API endpoint over HTTPS, with a private API key in shared headers; SQL Server connection strings and credentials stay entirely in Azure Function Application Settings.
Prerequisites
- A Bubble app on a paid plan if you need Backend Workflows for write operations; reads via client-side API Connector calls work on any plan
- The Bubble API Connector plugin installed (Plugins tab → Add plugins → search 'API Connector' by Bubble)
- Access to your SQL Server database credentials (or an existing .NET/Azure REST API already in place)
- An Azure account for deploying Azure Functions (or another hosting platform for your REST proxy)
- Access to someone on your team who knows the SQL Server database schema, or stored procedure documentation
Step-by-step guide
Assess whether an existing REST API already exposes your SQL Server data
Before building anything new, investigate whether your organization already has a REST layer in front of the SQL Server database. Ask the development team or check these common locations: 1. **Swagger/OpenAPI documentation**: Many ASP.NET Web API services auto-generate Swagger docs at `/swagger` or `/api/docs`. If this exists, you already have a REST API — note the base URL and auth mechanism. 2. **Azure API Management**: If your organization uses Azure, check the Azure Portal for an API Management instance that may already proxy the SQL Server application. 3. **OData endpoints**: .NET Entity Framework applications frequently expose OData v4 endpoints at `/odata/{Entity}`. These work with Bubble's API Connector — use `$filter`, `$select`, and `$top` query parameters for filtering. 4. **WCF or SOAP services**: If the only existing API is a WCF service or SOAP endpoint, Bubble's API Connector can call SOAP endpoints but the setup is complex. Consider wrapping the SOAP service in a thin Azure Function that converts it to REST/JSON. If an existing REST API exists: skip to Step 4 and configure Bubble's API Connector to point at that endpoint with the existing auth mechanism. If no REST API exists: continue with Steps 2 and 3 to deploy an Azure Function.
Pro tip: Even if a REST API exists, check whether it's designed for internal use only (protected by VPN, Windows Auth, or internal network access). If it requires VPN access, it cannot be called from Bubble's servers. In that case, you'll need to either open it to public internet (with proper auth) or deploy a new Azure Function that IS publicly accessible.
Expected result: You've determined whether an existing REST API is available. If yes, you have the base URL and auth mechanism. If no, you're ready to deploy an Azure Function in Steps 2–3.
Create an Azure Function App for SQL Server access
If you need to build a new REST layer, Azure Functions is the recommended platform because it integrates natively with Azure SQL, supports Managed Identity for passwordless auth, and scales automatically. In the Azure Portal, go to Create a resource → Function App. Configure: - **Runtime**: Node.js 20 LTS - **Plan**: Consumption (serverless, pay per execution — free tier covers 1M invocations/month) - **Region**: same region as your SQL Server instance (reduces latency) - **Operating System**: Linux After deployment, go to the Function App → Configuration → Application settings. Add these settings: - `SQL_CONNECTION_STRING`: your SQL Server connection string — for SQL Server Auth: `Server=your-server.database.windows.net;Database=your-db;User Id=your-user;Password=your-password;Encrypt=true;` - `BUBBLE_API_KEY`: a randomly generated API key string (you'll use this in Bubble's Private header to authenticate requests to the Function) For Azure SQL with Managed Identity (the more secure option for Azure-hosted databases): - Enable System-assigned Managed Identity on the Function App (Identity tab → System assigned → On) - In Azure SQL, run: `CREATE USER [your-function-app-name] FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER [your-function-app-name];` - Update the connection string to: `Server=your-server.database.windows.net;Database=your-db;Authentication=Active Directory Managed Identity;Encrypt=true;` Managed Identity eliminates the SQL Server password from your configuration entirely — the Function authenticates to SQL Server using its Azure identity.
1{2 "SQL_CONNECTION_STRING": "Server=your-server.database.windows.net;Database=your-db;User Id=your-user;Password=your-password;Encrypt=true;TrustServerCertificate=False;",3 "BUBBLE_API_KEY": "your-random-api-key-string"4}Pro tip: Azure SQL on the Serverless tier auto-pauses after a period of inactivity (default: 1 hour minimum auto-pause delay). The first Azure Function call after a pause triggers a database cold start that can take 15–30 seconds. Disable auto-pause for production databases under Azure SQL → Configure → Min vCores > 0 with Auto-pause delay set to -1 (disabled).
Expected result: Azure Function App deployed with Node.js runtime. SQL_CONNECTION_STRING and BUBBLE_API_KEY are set in Application Settings. The Function App URL is noted (e.g. https://your-function.azurewebsites.net).
Write Azure Function endpoints for your Bubble use cases
In the Azure Function App, create HTTP-triggered functions for each data operation your Bubble app needs. The key design principle: each function endpoint should correspond to a specific business operation, not generic SQL pass-through. Call stored procedures where they exist. Here's a sample Function that gets orders by status and creates new orders — using the `mssql` library with parameterized queries: ```javascript import sql from 'mssql'; const API_KEY = process.env.BUBBLE_API_KEY; const config = { connectionString: process.env.SQL_CONNECTION_STRING }; let pool; async function getPool() { if (!pool) pool = await sql.connect(config); return pool; } export default async function handler(req, context) { // Authenticate Bubble requests if (req.headers.get('x-api-key') !== API_KEY) { return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 }); } const db = await getPool(); const url = new URL(req.url); const path = url.pathname; if (req.method === 'GET' && path.endsWith('/orders')) { const status = url.searchParams.get('status'); const request = db.request(); let query = 'SELECT OrderId, CustomerId, Status, TotalAmount, CreatedAt FROM Orders'; if (status) { request.input('status', sql.NVarChar, status); query += ' WHERE Status = @status'; } query += ' ORDER BY CreatedAt DESC'; const result = await request.query(query); return new Response(JSON.stringify({ rows: result.recordset }), { headers: { 'Content-Type': 'application/json' } }); } if (req.method === 'POST' && path.endsWith('/orders')) { const body = await req.json(); const request = db.request(); // Use a stored procedure for the insert request.input('CustomerId', sql.Int, body.customerId); request.input('ProductId', sql.Int, body.productId); request.input('Quantity', sql.Int, body.quantity); const result = await request.execute('sp_CreateOrder'); return new Response(JSON.stringify({ orderId: result.recordset[0]?.OrderId }), { headers: { 'Content-Type': 'application/json' } }); } return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 }); } ``` Deploy the function. Test it from the Azure Portal's Function editor using the Test/Run panel, or with a REST client like Postman. Confirm it returns valid JSON before connecting Bubble.
1import sql from 'mssql';23const API_KEY = process.env.BUBBLE_API_KEY;4const config = { connectionString: process.env.SQL_CONNECTION_STRING };56let pool;7async function getPool() {8 if (!pool) pool = await sql.connect(config);9 return pool;10}1112export default async function handler(req, context) {13 if (req.headers.get('x-api-key') !== API_KEY) {14 return new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });15 }1617 const db = await getPool();18 const url = new URL(req.url);19 const path = url.pathname;2021 if (req.method === 'GET' && path.endsWith('/orders')) {22 const status = url.searchParams.get('status');23 const request = db.request();24 let query = 'SELECT OrderId, CustomerId, Status, TotalAmount, CreatedAt FROM Orders';25 if (status) {26 request.input('status', sql.NVarChar, status);27 query += ' WHERE Status = @status';28 }29 query += ' ORDER BY CreatedAt DESC';30 const result = await request.query(query);31 return new Response(JSON.stringify({ rows: result.recordset }), {32 headers: { 'Content-Type': 'application/json' }33 });34 }3536 if (req.method === 'POST' && path.endsWith('/orders')) {37 const body = await req.json();38 const request = db.request();39 request.input('CustomerId', sql.Int, body.customerId);40 request.input('ProductId', sql.Int, body.productId);41 request.input('Quantity', sql.Int, body.quantity);42 const result = await request.execute('sp_CreateOrder');43 return new Response(JSON.stringify({ orderId: result.recordset[0]?.OrderId }), {44 headers: { 'Content-Type': 'application/json' }45 });46 }4748 return new Response(JSON.stringify({ error: 'Not found' }), { status: 404 });49}Pro tip: Use `request.input('paramName', sql.DataType, value)` with the correct `mssql` data type (sql.Int, sql.NVarChar, sql.Decimal, sql.DateTime, etc.) for each parameter. Mismatched data types cause implicit conversions in SQL Server that can silently truncate data or cause query plan inefficiencies.
Expected result: Azure Function deployed and returning valid JSON for GET /orders and POST /orders. Testing with Postman confirms the x-api-key header is required and returns correct data from SQL Server.
Configure Bubble API Connector to call the Azure Function
In Bubble, go to Plugins tab → API Connector → 'Add another API'. Name it 'SQL Server API'. Set the base URL to your Azure Function URL: `https://your-function.azurewebsites.net/api` Add shared headers: - `x-api-key`: `{your-BUBBLE_API_KEY-value}` — check the **Private** checkbox - `Content-Type`: `application/json` Add your first call for reads: - **Name**: `Get Orders` - **Method**: GET - **URL**: `/orders` - **Parameters**: `status` (text, dynamic, optional) - **Use as**: Data Add a call for writes: - **Name**: `Create Order` - **Method**: POST - **URL**: `/orders` - **Body**: JSON `{"customerId": "{{customer_id}}", "productId": "{{product_id}}", "quantity": "{{quantity}}"}` - **Use as**: Action The full API Connector configuration: ```json { "base_url": "https://your-function.azurewebsites.net/api", "shared_headers": { "x-api-key": "<private>", "Content-Type": "application/json" }, "calls": [ { "name": "Get Orders", "method": "GET", "path": "/orders", "params": { "status": "<dynamic-optional>" }, "use_as": "Data" }, { "name": "Create Order", "method": "POST", "path": "/orders", "body": { "customerId": "<dynamic>", "productId": "<dynamic>", "quantity": "<dynamic>" }, "use_as": "Action" } ] } ``` For Initialize call on 'Get Orders': click Initialize call → Run. If your SQL Server Orders table has data, Bubble detects the field schema from the `rows` array. If Azure SQL Serverless is paused when you initialize, the first call may time out — go to the Azure Portal and trigger a query from the SQL Server Query editor to wake the database first. For Initialize call on 'Create Order': provide test values and run. The Function should return `{"orderId": 123}` (or whatever your stored procedure returns). Save.
1{2 "base_url": "https://your-function.azurewebsites.net/api",3 "shared_headers": {4 "x-api-key": "<private>",5 "Content-Type": "application/json"6 },7 "calls": [8 {9 "name": "Get Orders",10 "method": "GET",11 "path": "/orders",12 "params": { "status": "<dynamic-optional>" },13 "use_as": "Data"14 }15 ]16}Pro tip: If your Azure Function URL includes a function-level API key (visible in the Function App → Functions → your function → Function key), add it as a query parameter `code={functionKey}` to the base URL rather than as a separate header. This is Azure's own auth layer on top of your BUBBLE_API_KEY check — both can be active simultaneously for defense in depth.
Expected result: The SQL Server API group is configured in Bubble's API Connector with the x-api-key shared header marked Private. 'Get Orders' (Data) and 'Create Order' (Action) calls are initialized and Bubble has detected the response field schema.
Build Bubble workflows for SQL Server reads and writes
With initialized API calls, wire them to your Bubble UI elements. **Reads in a Repeating Group**: Set the Repeating Group's Data source to 'Get Orders' (or your specific GET call). Add a filter Dropdown above the repeating group for status filtering — set the `status` parameter in the Data source to `Dropdown Filter's value`. Bubble re-fetches the API when the dropdown selection changes. Each row displays `current cell's Get Orders result's OrderId`, `current cell's Get Orders result's Status`, etc. **Writes via Backend Workflow**: For create, update, and delete operations, route them through a Backend Workflow (paid plan). In the Backend Workflows section, create 'Create SQL Order' with parameters `customer_id` (number), `product_id` (number), `quantity` (number). Add action: Plugins → API Connector → Create Order. Map parameters from the workflow parameters. Return the `orderId` from the action result. Trigger from client: button click → Schedule API Workflow → 'Create SQL Order' → pass `customer_id = Customer Dropdown's value's id`, `product_id = Product Dropdown's value's id`, `quantity = Quantity Input's value`. After a successful write, refresh the repeating group data source by triggering the Get Orders call again (add a 'Display data' action or reload the data source). **Handling write results**: In the Backend Workflow, after the Create Order action, access the result with `Step 1's orderId`. If your Bubble app needs to track this order ID for follow-up actions (e.g. redirect to an order detail page), store it in a Bubble data type or pass it back to the page through a custom state. RapidDev's team has built Bubble integrations with SQL Server for enterprise ERP systems and Azure SQL data warehouses — if your SQL Server environment has specific authentication requirements (Windows Auth, Azure AD), book a free scoping call at rapidevelopers.com/contact.
Pro tip: Add a 'Loading' state to your Bubble page UI for SQL Server queries — especially if Azure SQL Serverless auto-pause is a possibility. Use a custom state 'is_loading' (boolean): set it to true before the API call action, set it back to false in a 'trigger another event' action after the API call completes. Show a loading spinner when is_loading is true.
Expected result: A Bubble Repeating Group displays SQL Server data fetched via the Azure Function. A button workflow triggers a Backend Workflow that creates a new SQL Server record via the stored procedure. The Azure Function logs (in Azure Portal → Functions → Monitor) confirm successful executions.
Handle Azure SQL cold starts and add error handling
Azure SQL Serverless tier's auto-pause is the most common operational issue for Bubble + SQL Server integrations. When the database hasn't been queried for the auto-pause threshold (default 1 hour minimum), the first request triggers a cold start. In Bubble's API Connector call settings, increase the timeout for SQL Server calls. In the API Connector, click the gear icon on the 'Get Orders' call → increase the timeout to 60 seconds. This gives Azure SQL time to resume from a paused state before Bubble declares the call timed out. Add a retry mechanism in your Bubble workflows: after a SQL Server API call action, add a conditional branch: 'If Step 1 failed → wait 5 seconds → try API call again (Step 3)'. This handles temporary cold-start failures without showing a user-facing error. For the long-term fix, either disable Azure SQL auto-pause for production: - Azure Portal → your Azure SQL database → Configure → Min vCores (set to 0.5 or higher) → Auto-pause delay (set to -1 to disable) Or add a health check call in Bubble: a lightweight API Connector call (GET /health that returns `{"status": "ok"}` from the Azure Function with a simple `SELECT 1` SQL) that fires on page load before the user sees any data fetch. This proactively wakes Azure SQL before the user interacts. Add Bubble privacy rules on any data types that cache SQL Server data in Bubble's native database: Data tab → [Data type] → Privacy → add a rule restricting reads to the data owner. This adds a Bubble-side access control layer on top of the SQL Server-side restrictions enforced in the Azure Function.
Pro tip: Monitor your Azure Function execution logs in Azure Portal → Function App → Functions → [function name] → Monitor → Invocations. Filter for errors to see SQL Server connection failures, parameter type errors, and stored procedure exceptions with their full stack traces — much more diagnostic detail than Bubble's API Connector logs alone.
Expected result: The API Connector call timeout is increased to handle Azure SQL cold starts. A health check call on page load proactively wakes the database. Error handling in Bubble workflows provides users with clear feedback on SQL Server errors rather than silent failures.
Common use cases
Bubble frontend for a Dynamics 365 or ERP backend
Build a custom Bubble web app that surfaces data from an existing Dynamics 365 or custom .NET ERP system running on SQL Server — a customer portal, a field service app, or a data entry form — without requiring users to log in to the full ERP system. The Azure Function queries specific stored procedures and returns only the data Bubble needs.
Build a Bubble portal where sales reps can view their assigned accounts and open opportunities from Dynamics 365 SQL Server, search by company name, and update the opportunity stage — all without logging into the Dynamics CRM interface.
Copy this prompt to try it in Bubble
Internal admin dashboard for legacy SQL Server application
Replace a clunky internal .NET winforms or web forms admin tool with a modern Bubble dashboard that calls the same SQL Server database via Azure Functions. Non-technical operations staff get a clean, mobile-responsive interface; the database and business logic stay unchanged.
Create a Bubble admin panel that calls an Azure Function with endpoints GET /orders?status=pending and PATCH /orders/{id}/status — the function executes stored procedures against the existing SQL Server Order Management database and returns JSON.
Copy this prompt to try it in Bubble
Reporting dashboard from Azure SQL data warehouse
Pull aggregated metrics and KPIs from an Azure SQL data warehouse or OLAP database into a Bubble reporting dashboard with charts and tables. The Azure Function executes read-only reporting stored procedures and returns summarized JSON — Bubble displays it in Recharts-equivalent repeating groups and text elements.
Build a Bubble executive dashboard that calls an Azure Function executing the sp_GetMonthlySalesKPIs stored procedure, returns JSON with revenue, units, and margin metrics, and displays them in text elements and a chart plugin.
Copy this prompt to try it in Bubble
Troubleshooting
Bubble API Connector Initialize call times out during the first call after a period of inactivity
Cause: Azure SQL Serverless tier paused the database due to inactivity. The first query triggers a cold start that takes 15–30 seconds — longer than Bubble's default API Connector timeout.
Solution: Increase the API Connector call timeout to 60 seconds in the call settings. Additionally, trigger a query from the Azure Portal's SQL Query editor to wake the database before running the Initialize call in Bubble. For production, disable Azure SQL auto-pause: Azure Portal → your database → Configure → Auto-pause delay → set to -1 (disabled).
Azure Function returns 401 Unauthorized when called from Bubble
Cause: The x-api-key header value in Bubble's API Connector doesn't match the BUBBLE_API_KEY Application Setting in the Azure Function App.
Solution: In the Azure Portal, go to your Function App → Configuration → Application settings → verify the BUBBLE_API_KEY value. In Bubble's API Connector, open the SQL Server API group and verify the x-api-key header value matches exactly (no extra spaces, correct case). If you recently updated the Application Setting, the Function App may need a restart to pick up the new value — go to the Function App → Overview → Restart.
SQL Server query returns unexpected results or the mssql function throws a type conversion error
Cause: The parameter type passed from Bubble to the Azure Function's `request.input()` call doesn't match the SQL Server column type. For example, passing a string where the function expects sql.Int causes a conversion error.
Solution: In the Azure Function code, verify the `sql.DataType` in `request.input('paramName', sql.DataType, value)` matches the column type in SQL Server. Common mismatches: Bubble text inputs send strings, but SQL Server INT columns expect numbers — convert in the Function with `parseInt(body.customerId, 10)`. Check the Azure Function's Monitor logs for the exact SQL Server error message.
Windows Authentication is required for the SQL Server connection but the Azure Function returns connection errors
Cause: Windows Authentication (Integrated Security) requires the connecting process to have an Active Directory identity. A basic Azure Function with a username/password connection string cannot use Windows Auth unless Managed Identity is configured.
Solution: Use Azure Managed Identity instead of Windows Auth. Enable System-assigned Managed Identity on the Function App (Identity tab → On), then grant the Function App access to Azure SQL: in Azure SQL, run `CREATE USER [your-function-name] FROM EXTERNAL PROVIDER; ALTER ROLE db_datareader ADD MEMBER [your-function-name];`. Update the connection string to `Authentication=Active Directory Managed Identity`. For on-premises SQL Server with Windows Auth, a VPN or Azure Hybrid Connection is required — this is a significantly more complex setup.
Bubble API Connector Initialize call shows 'There was an issue setting up your call' with no clear error
Cause: The Azure Function returned a non-200 status code or an invalid JSON response during initialization. Common causes: the Function App isn't deployed, the SQL Server table is empty (empty JSON array means Bubble can't detect fields), or the Function code threw an uncaught exception.
Solution: Test the Azure Function endpoint directly with a REST client (Postman or the Azure Portal's Test/Run panel) to get the raw response. Check Azure Function Monitor logs for uncaught exceptions. If the SQL Server table is empty, insert a test row and re-initialize. If the Function returns HTML error pages instead of JSON, add proper error handling in the Function code.
Best practices
- Check whether an existing REST API already sits in front of your SQL Server before building a new Azure Function. Many enterprise .NET environments already have ASP.NET Web API, OData, or Azure API Management endpoints — reusing them is faster and avoids duplicating business logic.
- Use stored procedures for write operations (INSERT, UPDATE, DELETE) rather than direct SQL in your Azure Function. Stored procedures keep T-SQL business logic in the database, give DBAs control over what Bubble can modify, enforce audit logging, and benefit from SQL Server's query plan caching.
- Use typed parameters with mssql's `request.input('name', sql.DataType, value)` for every query parameter. Explicit typing prevents implicit SQL Server type conversions that can silently corrupt data or cause query plan inefficiencies.
- Design REST endpoints around business operations, not generic SQL pass-through. An endpoint like GET /pending-orders is safer and more maintainable than a generic /query endpoint that accepts raw SQL strings — even with authentication, generic SQL endpoints allow any operation on any table.
- Disable Azure SQL Serverless auto-pause for production databases. Cold starts of 15–30 seconds are unacceptable for user-facing Bubble applications. Set auto-pause delay to -1 (disabled) in the Azure SQL configuration, or move to the General Purpose / Business Critical tier for predictable performance.
- Store the SQL Server connection string in Azure Function Application Settings (encrypted at rest), never in Bubble's API Connector fields or any client-visible configuration. Bubble's Private header hides the API key from the browser, but the connection string must never reach Bubble at all.
- Add a health check endpoint to your Azure Function (GET /health → SELECT 1 → return {"status": "ok"}) and call it from Bubble's page load workflow before any data fetches. This proactively wakes Azure SQL from a paused state before the user sees any data tables.
- Route all write operations through Bubble Backend Workflows (paid plan) rather than client-side API Connector calls. Backend Workflows run on Bubble's servers, keep write calls off the browser DevTools network panel, and centralize write logic for easier debugging.
Alternatives
Supabase wraps PostgreSQL with an auto-generated REST API and Row Level Security — zero custom backend code required, and the free tier works for most initial projects. If you're not committed to SQL Server and don't have an existing SQL Server database, Supabase/PostgreSQL is far easier to integrate with Bubble.
MySQL is more common in LAMP/PHP stacks and has PlanetScale as a managed HTTP API option with no server to deploy. If you're building a new application and choosing between MySQL and SQL Server, MySQL with PlanetScale is quicker to set up in Bubble. SQL Server is the right choice only when you have existing SQL Server infrastructure or .NET team conventions.
Airtable connects to Bubble with a simple Personal Access Token and no custom backend — the most beginner-friendly option. It's appropriate for small datasets (up to 125,000 records on Business plan) managed by non-technical teams. SQL Server is for enterprise relational data at scale with complex business logic.
Frequently asked questions
Can I use Windows Authentication or Azure Active Directory auth with Bubble + SQL Server?
Not directly from Bubble — Windows Authentication requires the client to have an Active Directory identity, which a browser cannot have. The authentication must happen server-side in your Azure Function. For Azure SQL with Azure AD auth, use Azure Managed Identity on the Function App — the Function authenticates to Azure SQL via its Azure AD identity, and Bubble authenticates to the Function via an API key. This is the most secure option for Azure SQL.
What's the difference between SQL Server Authentication and Windows Authentication for this integration?
SQL Server Authentication uses a username and password in the connection string — simpler to configure but requires managing credentials. Windows Authentication uses Active Directory identities — more secure but requires Azure Managed Identity or a service account in AD to work from a cloud function. For most Bubble + SQL Server integrations, SQL Server Authentication with a dedicated read/write account (not sa/admin) is the pragmatic choice. Enterprise environments with Azure AD should use Managed Identity.
Why should I use stored procedures instead of direct SQL queries in the Azure Function?
Stored procedures keep business logic in the database where DBAs and enterprise governance tools can see and control it. They enforce consistent audit logging, support complex multi-table transactions that are difficult to replicate in application code, and benefit from SQL Server's query plan caching. For enterprise SQL Server databases, stored procedures are the expected integration pattern — your DBA team likely already has relevant stored procedures for common operations.
Is there a way to avoid deploying an Azure Function for SQL Server access?
Yes — if your existing .NET application already exposes a REST or OData API, point Bubble's API Connector directly at it. Many enterprise .NET systems have ASP.NET Web API endpoints that return JSON, OData v4 feeds from Entity Framework, or Azure API Management policies that expose SQL Server data. Check with your dev team before building a new Azure Function.
What happens if Azure SQL Serverless pauses while my Bubble app is being used?
Azure SQL pauses automatically after a configurable period without queries (default minimum is 1 hour, but the actual pause happens after the min auto-pause delay elapses without activity). If a user makes a Bubble API call while SQL is paused, the first query triggers a cold start that takes 15–30 seconds. The Azure Function will time out if Bubble's API Connector timeout is set too low. Either disable auto-pause for production (recommended) or increase the Bubble API Connector call timeout to 60 seconds and add a retry logic in the workflow.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation