Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

MongoDB

Connect Bubble to MongoDB Atlas using a thin REST proxy — a Node.js service on Render or Railway that holds your MongoDB connection string and exposes clean HTTPS endpoints. Bubble's API Connector calls those endpoints with a Private API key header, keeping credentials server-side. The old Atlas Data API was retired in September 2025 and no longer works; a custom proxy or Atlas App Services custom HTTPS endpoint is required.

What you'll learn

  • Why the Atlas Data API retirement (September 2025) changes the Bubble + MongoDB architecture
  • How to deploy a Node.js REST proxy on Render free tier for the mongodb driver
  • How to configure Bubble's API Connector with a Private API key header for the proxy
  • How to initialize Bubble data types from MongoDB document structures using 'Use as Data'
  • How to handle MongoDB ObjectID (`_id` as `{"$oid":"..."}`) in Bubble workflows
  • How to paginate MongoDB results in Bubble Repeating Groups using limit and offset
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate17 min read90 minutesDatabase & BackendLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to MongoDB Atlas using a thin REST proxy — a Node.js service on Render or Railway that holds your MongoDB connection string and exposes clean HTTPS endpoints. Bubble's API Connector calls those endpoints with a Private API key header, keeping credentials server-side. The old Atlas Data API was retired in September 2025 and no longer works; a custom proxy or Atlas App Services custom HTTPS endpoint is required.

Quick facts about this guide
FactValue
ToolMongoDB
CategoryDatabase & Backend
MethodBubble API Connector
DifficultyIntermediate
Time required90 minutes
Last updatedJuly 2026

The 2026 Bubble + MongoDB architecture after Atlas Data API retirement

Until September 2025, connecting Bubble to MongoDB Atlas was relatively straightforward: the Atlas Data API exposed an HTTPS endpoint at `data.mongodb-api.com` that accepted JSON requests without a driver. That API was retired and those endpoints now return 404 or 410 errors. Any tutorial you find referencing `data.mongodb-api.com` is outdated — those instructions no longer work.

The current 2026 architecture has two options. Option A (recommended for most teams): deploy a small Node.js REST proxy — a ~50-line Express service using the `mongodb` npm package — on Render's free tier or Railway. The proxy holds the `mongodb+srv://` connection string in an environment variable, validates an incoming API key header, and translates Bubble's HTTPS calls into MongoDB find/insert/update operations. Option B (no separate infrastructure): use MongoDB Atlas App Services custom HTTPS endpoints (Functions). These are hosted by MongoDB and act as a managed proxy layer — but availability on the free M0 cluster tier should be verified in current Atlas documentation before committing to this approach.

Bubble's API Connector handles both options identically: a base URL, a Private API key header, and individual calls for each database operation. Because Bubble's API Connector proxies all calls through Bubble's servers, the proxy API key never reaches any user's browser.

MongoDB Atlas M0 (free tier) provides 512MB shared storage and supports up to your application's data needs during development. Dedicated M10 clusters start at approximately $0.08/hr — verify current pricing at atlas.mongodb.com.

Integration method

Bubble API Connector

Call a custom Node.js REST proxy (or Atlas App Services endpoint) from Bubble's API Connector using a Private API key header.

Prerequisites

  • A Bubble app on any plan (Free plan works for API Connector; paid Bubble plan required for API Workflows / Backend Workflows)
  • A MongoDB Atlas account at mongodb.com/atlas (M0 free cluster available)
  • A Render account at render.com (free tier available for the proxy service)
  • The API Connector plugin installed in your Bubble app (Plugins tab → Add plugins → search 'API Connector' by Bubble → Install)
  • Basic understanding of JSON object structure

Step-by-step guide

1

Create a MongoDB Atlas cluster and database user

Go to mongodb.com/atlas and sign in or create a free account. Click 'Build a Database' and choose the M0 free shared cluster. Select your preferred cloud provider and region closest to your Render proxy deployment (both on the same continent reduces latency). Once the cluster is provisioned, click 'Database Access' in the left sidebar and add a new database user. Give it a username like `bubble-proxy` and a secure auto-generated password — copy this password immediately as you cannot retrieve it later. Set the role to 'Read and Write to Any Database' for development; restrict to specific databases in production. Next, click 'Network Access' and add an IP address. For the Render proxy on Render's free tier, use `0.0.0.0/0` (allow all) since Render does not provide static outbound IPs. In production, consider upgrading to a paid Render plan that provides a static IP and whitelist only that IP. Finally, click 'Databases' → 'Connect' → 'Connect your application' and copy the `mongodb+srv://` connection string. Replace `<password>` in the string with your database user password.

Pro tip: When naming your Atlas cluster, avoid special characters. A simple name like 'bubble-prod' or 'myapp-cluster' is easier to reference. The cluster name appears in the connection string but does not affect functionality.

Expected result: Your Atlas cluster is running (green status indicator). You have a database user with read/write access and the `mongodb+srv://` connection string copied. Network access is configured to allow your proxy's IP range.

2

Deploy a Node.js REST proxy on Render

Create a new GitHub repository and add two files: `package.json` and `server.js`. In `package.json` declare dependencies on `express` and `mongodb`. In `server.js`, create an Express server that validates an incoming `X-API-Key` header against an environment variable, connects to MongoDB using the `mongodb` driver, and exposes three routes: `POST /find` (accepts `collection`, `filter`, `limit`, `skip`), `POST /insertOne` (accepts `collection`, `document`), and `POST /updateOne` (accepts `collection`, `filter`, `update`). In each route, convert `_id` ObjectID values to plain strings before returning the JSON response to Bubble. Go to render.com, create a new Web Service, connect your GitHub repository, set the environment variable `MONGO_URI` to your connection string and `API_KEY` to a strong secret you generate (use a random 32-character string). Deploy. Once live, Render provides a public HTTPS URL like `https://your-proxy.onrender.com`. Test it with a direct HTTPS POST request to confirm it returns MongoDB documents.

server.js
1// server.js — minimal MongoDB proxy for Bubble
2const express = require('express');
3const { MongoClient, ObjectId } = require('mongodb');
4const app = express();
5app.use(express.json());
6
7const client = new MongoClient(process.env.MONGO_URI);
8let db;
9
10async function connect() {
11 await client.connect();
12 db = client.db(); // uses database from connection string
13 console.log('MongoDB connected');
14}
15connect();
16
17function authMiddleware(req, res, next) {
18 if (req.headers['x-api-key'] !== process.env.API_KEY) {
19 return res.status(401).json({ error: 'Unauthorized' });
20 }
21 next();
22}
23
24function serializeDocs(docs) {
25 return docs.map(doc => ({
26 ...doc,
27 _id: doc._id ? doc._id.toString() : undefined
28 }));
29}
30
31app.post('/find', authMiddleware, async (req, res) => {
32 const { collection, filter = {}, limit = 25, skip = 0 } = req.body;
33 const docs = await db.collection(collection)
34 .find(filter).limit(limit).skip(skip).toArray();
35 res.json({ documents: serializeDocs(docs) });
36});
37
38app.post('/insertOne', authMiddleware, async (req, res) => {
39 const { collection, document } = req.body;
40 const result = await db.collection(collection).insertOne(document);
41 res.json({ insertedId: result.insertedId.toString() });
42});
43
44app.post('/updateOne', authMiddleware, async (req, res) => {
45 const { collection, filter, update } = req.body;
46 if (filter._id) filter._id = new ObjectId(filter._id);
47 const result = await db.collection(collection).updateOne(filter, update);
48 res.json({ modifiedCount: result.modifiedCount });
49});
50
51app.listen(process.env.PORT || 3000);

Pro tip: Render free tier services spin down after 15 minutes of inactivity and take a few seconds to cold-start. For production Bubble apps, upgrade to a paid Render instance (always-on) or use Railway, which has more predictable startup behavior on its free tier.

Expected result: Your Render proxy is live at a public HTTPS URL. You can test a POST to `/find` with the `X-API-Key` header and receive a JSON response from your MongoDB collection (or an empty `documents` array if the collection is empty).

3

Configure the Bubble API Connector to call the proxy

In your Bubble editor, go to the Plugins tab. If 'API Connector' by Bubble is not installed, click 'Add plugins', search 'API Connector', and install it. Click 'API Connector' in your plugins list, then 'Add another API'. Name it 'MongoDB Proxy'. In the 'Root URL' field, paste your Render proxy's HTTPS URL (e.g., `https://your-proxy.onrender.com`). In the 'Shared headers' section, click 'Add a shared header'. Key: `X-API-Key`. Value: the API key you set in your Render environment variable. Check the 'Private' checkbox — this is mandatory. The Private checkbox ensures Bubble processes this header on its servers and never sends the raw API key to any browser. Add a second shared header: Key `Content-Type`, Value `application/json` (leave this one as Client-safe since it is not a secret). Now you are ready to add individual operation calls.

mongodb-proxy-connector-config.json
1{
2 "root_url": "https://your-proxy.onrender.com",
3 "shared_headers": [
4 {
5 "key": "X-API-Key",
6 "value": "<your-proxy-api-key>",
7 "private": true
8 },
9 {
10 "key": "Content-Type",
11 "value": "application/json",
12 "private": false
13 }
14 ]
15}

Pro tip: Give the API Connector group a clear name like 'MongoDB Proxy' so future team members immediately understand what it connects to. Add a 'Description' at the group level explaining this is a proxy for Atlas and noting the repository URL where the proxy code lives.

Expected result: The 'MongoDB Proxy' API group appears in your API Connector plugin with the root URL and two shared headers configured. The X-API-Key header shows a lock icon or 'Private' indicator confirming it will not be sent to browsers.

4

Create the FindDocuments call and initialize it for 'Use as Data'

Inside the 'MongoDB Proxy' API group, click 'Add another call'. Name it 'FindDocuments'. Set method to POST. Set the endpoint to `/find`. In the 'Body' section (JSON), add three parameters: `collection` (text, example value: your collection name like `products`), `limit` (number, example value: `25`), `skip` (number, example value: `0`). Click 'Initialize the call'. Bubble makes a real POST request to your proxy, which queries MongoDB and returns real documents. If your collection has documents, they appear in the response under the `documents` array. If empty, add a test document to your MongoDB collection first via the Atlas UI. Once Bubble shows the response, configure 'Use as' to 'Data'. Bubble detects the `documents` array and prompts you to map the inner document structure to a Bubble data type. Name this type something like 'MongoProduct'. Each field in your MongoDB documents becomes a field on this type. The `_id` field — which your proxy already converted to a plain string — maps as a Text field. This is the ID you store and use for future updateOne calls.

mongodb-find-call.json
1// FindDocuments call body
2{
3 "collection": "products",
4 "limit": 25,
5 "skip": 0
6}
7
8// Sample response from proxy
9{
10 "documents": [
11 {
12 "_id": "64f8a2b3c1d2e3f4a5b6c7d8",
13 "name": "Widget Pro",
14 "price": 29.99,
15 "category": "tools",
16 "in_stock": true
17 }
18 ]
19}

Pro tip: Initialize with a document that has all the fields your Bubble app needs to display. If you initialize with an incomplete document, Bubble's detected data type will be missing fields. You can re-initialize later but it regenerates the type and may disconnect existing bindings.

Expected result: The FindDocuments call initializes successfully. Bubble creates a 'MongoProduct' data type with fields matching your document structure including `_id` as Text. The call is set to 'Use as Data' and can be used as a data source in Repeating Groups and display elements.

5

Create InsertOne and UpdateOne calls

Add a new call named 'InsertDocument'. Set method to POST, endpoint to `/insertOne`. In the body, add two parameters: `collection` (text) and `document` (object — paste a representative JSON object of the document structure you will insert, with all required fields). Set 'Use as' to 'Action'. Add another call named 'UpdateDocument'. Set method to POST, endpoint to `/updateOne`. Body parameters: `collection` (text), `filter` (object — include `_id` as the primary filter: `{"_id": "<dynamic_id>"}`), and `update` (object — use MongoDB update syntax: `{"$set": {"field": "new_value"}}`). Set 'Use as' to 'Action'. Initialize both calls with real test data. When testing InsertDocument, check your MongoDB Atlas collection in the browser to confirm the document was inserted. For UpdateDocument, use the `_id` string from a real document in your collection. After initializing, delete any test documents created during initialization from Atlas if you do not want them in production data.

mongodb-write-calls.json
1// InsertDocument body
2{
3 "collection": "products",
4 "document": {
5 "name": "{{name}}",
6 "price": "{{price}}",
7 "category": "{{category}}",
8 "created_at": "{{created_at}}"
9 }
10}
11
12// UpdateDocument body
13{
14 "collection": "products",
15 "filter": { "_id": "{{doc_id}}" },
16 "update": { "$set": { "name": "{{name}}", "price": "{{price}}" } }
17}

Pro tip: For RapidDev clients, we recommend wrapping all MongoDB write operations in Bubble's 'Schedule API workflow' for asynchronous processing — especially insert operations that run after form submissions. This prevents the 30-second workflow timeout from affecting user experience on slow proxy cold-starts. Scoping discussion available at rapidevelopers.com/contact.

Expected result: You have three working API Connector calls: FindDocuments (Use as Data), InsertDocument (Action), and UpdateDocument (Action). Test each from the API Connector editor to confirm they return the expected responses before building Bubble UI on top of them.

6

Build Bubble workflows and Repeating Groups to display and write data

Now connect everything to your Bubble UI. For displaying data: add a Repeating Group to your page. Set its data source to 'Get data from an external API' → FindDocuments. Pass the `collection` name as a fixed value (e.g., `products`) and `limit` as `25`. Set `skip` to `(currentPage - 1) × 25` using a custom state named `currentPage` (initialized to `1`) for pagination. Each cell in the Repeating Group binds to the detected MongoProduct type fields: `current cell's MongoProduct's name`, `current cell's MongoProduct's price`, etc. For inserting data: create a 'Submit form' workflow. Add the API Connector action 'InsertDocument' and map each input field to the corresponding `document` body parameter. For updating: when a user clicks an Edit button on a Repeating Group row, store the `current cell's MongoProduct's _id` in a custom state. In the update workflow, pass that stored ID as the `filter._id` parameter and the updated field values in `update.$set`. Set up privacy rules for any Bubble data types you create from MongoDB documents under Data tab → Privacy to control which users can read or modify records in Bubble's UI.

Pro tip: Bubble's 30-second workflow timeout applies to all API calls including the proxy. Large MongoDB find operations without a `limit` can time out. Always pass a `limit` parameter in FindDocuments and test with realistic data volumes before going live.

Expected result: Your Bubble Repeating Group populates with MongoDB documents on page load. The insert form creates new MongoDB documents via the proxy. The edit flow updates existing documents using the stored `_id` string. Pagination works using the custom state for the `skip` offset parameter.

Common use cases

Product catalog with flexible schema

Store a product catalog where different product types have different attributes — electronics have voltage specs, clothing has sizes and materials, food has allergen lists. MongoDB's schema-flexible documents handle this naturally where SQL would require multiple tables. Your Bubble app queries the proxy's /find endpoint filtered by product category and populates a Repeating Group. Each document type can have different fields without breaking the collection structure.

Bubble Prompt

Build a Bubble page that loads a product catalog from MongoDB via a REST proxy. The Repeating Group shows products filtered by a Category dropdown. Clicking a product opens a popup that displays all available fields for that document, even if different products have different fields.

Copy this prompt to try it in Bubble

User-generated content with nested data

Store blog posts, forum threads, or reviews as MongoDB documents where each document contains the content body, author metadata, and an array of nested comments — all in one document. Your Bubble app inserts documents via the proxy's insertOne endpoint when users submit content, and retrieves them with find. This avoids the multi-table JOIN complexity required for the same structure in SQL.

Bubble Prompt

Create a Bubble workflow that inserts a new blog post document into MongoDB via the proxy when a user submits a form. The document should include title, body, author ID, timestamp, and an initial empty comments array. After insertion, refresh the posts Repeating Group to show the new entry.

Copy this prompt to try it in Bubble

Activity logging and event tracking

Append user activity events (page views, button clicks, purchase attempts) as MongoDB documents. MongoDB's flexible schema lets you include different metadata per event type without schema migrations. Your proxy exposes an insertOne endpoint that Bubble calls on each relevant user action, and an aggregation endpoint for your admin Bubble dashboard to display activity summaries.

Bubble Prompt

Set up a Bubble workflow that fires on page load and calls the MongoDB proxy insertOne endpoint to log a page view event. The document should include user ID, page name, timestamp, and any relevant context. The admin dashboard uses a find call with a date filter to show today's activity.

Copy this prompt to try it in Bubble

Troubleshooting

API Connector initialize call fails with 'There was an issue setting up your call' or returns 404

Cause: This happens when the Bubble API Connector cannot reach your proxy. The proxy may be cold-starting (Render free tier spins down after 15 minutes), the root URL may have a trailing slash that conflicts with the endpoint path, or the X-API-Key header value may not match the environment variable in Render.

Solution: First, wait 30 seconds and try initializing again if the proxy was cold-starting. Check the Render dashboard logs to see if the service started successfully. Verify the root URL has no trailing slash. Confirm the X-API-Key value in Bubble matches the API_KEY environment variable in Render exactly, including case. Click 'Initialize the call' again once you have confirmed the proxy is running.

MongoDB documents appear in Atlas but the FindDocuments call returns an empty documents array

Cause: The collection name passed in the body does not exactly match the collection name in Atlas (MongoDB collection names are case-sensitive), or the database user does not have read access to that specific collection.

Solution: Check the collection name in the Atlas UI under Browse Collections. Ensure the `collection` body parameter in your Bubble API Connector call matches exactly — for example, `Products` and `products` are different collections in MongoDB. Also verify your database user's role includes access to the specific database and collection in Atlas → Database Access.

UpdateOne returns 'modifiedCount: 0' but no error — the document was not updated

Cause: The `_id` filter value does not match any document. Either the ID stored in Bubble's custom state is empty, or the proxy's ObjectId conversion logic is receiving a malformed string.

Solution: Log the `_id` value from the custom state before the UpdateDocument call using a Bubble 'Show an alert' action to confirm it is a valid 24-character hex string. If the ID is empty, trace back to where you stored it — the Repeating Group cell's `_id` field must be populated correctly from the FindDocuments response. If it is populated but the update still fails, check your proxy's `filter._id = new ObjectId(filter._id)` conversion handles the string correctly.

Bubble API Connector shows the proxy endpoint returns data.mongodb-api.com 404 errors

Cause: Your proxy (or an old tutorial you followed) is still calling the retired Atlas Data API at `data.mongodb-api.com`. This endpoint was retired in September 2025 and returns 404/410 errors.

Solution: Update your proxy to use the `mongodb` npm driver directly with the `mongodb+srv://` connection string, not the Atlas Data API endpoint. The server.js code in Step 2 of this guide uses the correct driver-based approach. Delete any calls to `data.mongodb-api.com` from your proxy.

Bubble workflow times out after 30 seconds when fetching MongoDB data

Cause: The MongoDB find operation has no limit, returns thousands of documents, or the Render free tier proxy is experiencing a cold start delay on top of a slow query.

Solution: Add `"limit": 25` to all FindDocuments calls. Check the Render logs for query execution time. If cold starts are causing timeouts, upgrade to a paid Render instance (always-on) or implement a health-check ping from Bubble on page load to wake the proxy before the user triggers a data-loading workflow.

Best practices

  • Always mark your proxy's API key as Private in the Bubble API Connector shared header. Never use Client-safe for credentials that can access your MongoDB database.
  • Convert `_id` ObjectID to a plain string in your proxy before returning JSON to Bubble. Returning `{"$oid":"..."}` objects to Bubble creates complex nested types that are difficult to bind in Repeating Groups and impossible to use as filter values without extra steps.
  • Add `limit` to every MongoDB find operation in your proxy and in every Bubble API call. Without limits, a growing collection can exceed Bubble's 30-second workflow timeout and return unmanageable data volumes.
  • Set up Data tab → Privacy rules in Bubble for any data types you create from MongoDB documents. Without privacy rules, Bubble's built-in search and data operations may expose records across users.
  • Use environment variables for ALL credentials in your Render proxy: MONGO_URI and API_KEY should never appear in your source code or GitHub repository. Add a `.gitignore` entry for `.env` files.
  • For the Render free tier proxy, implement a connection pooling strategy in your server.js — connect once at startup (not per request) and reuse the connection. The code in Step 2 does this correctly. Per-request connections exhaust MongoDB Atlas M0's connection limit quickly.
  • Use the Bubble Logs tab (left sidebar in editor) to debug API call failures. Bubble shows the request it sent and the response it received, making it easy to spot mismatched keys, wrong endpoints, or authentication failures without needing to check Render logs separately.

Alternatives

Frequently asked questions

Is the Atlas Data API coming back, or do I need a proxy permanently?

The Atlas Data API was officially retired by MongoDB in September 2025 and there are no announced plans to reinstate it. The supported paths going forward are: (1) a custom REST proxy using the mongodb driver (the approach in this guide), or (2) MongoDB Atlas App Services custom HTTPS endpoints (managed by MongoDB). Both are stable, production-ready architectures. The proxy approach gives you more control; Atlas App Services gives you less infrastructure to manage.

Can I use MongoDB Atlas App Services endpoints instead of a Render proxy?

Yes. Atlas App Services allows you to write JavaScript functions that query MongoDB and expose them as HTTPS callable endpoints. This avoids running separate proxy infrastructure. The setup is done entirely in the Atlas App Services UI (Atlas → App Services → Create App → HTTPS Endpoints). However, Atlas App Services function availability on the free M0 tier may be limited — verify current feature availability in the Atlas documentation before building your Bubble integration around this approach.

How do I handle the MongoDB _id field in Bubble workflows for updates and deletes?

Your proxy should convert `_id` from a MongoDB ObjectID to a plain string before returning JSON to Bubble (using `doc._id.toString()`). In Bubble, store this string in a custom state when a user clicks an edit or delete button in a Repeating Group. Pass the stored string as the `filter._id` value in your UpdateDocument or a DeleteDocument call. The proxy converts it back to a MongoDB ObjectID using `new ObjectId(filter._id)` before running the update or delete operation.

Do I need a paid Bubble plan to use MongoDB with Bubble?

Basic read and write operations via the API Connector work on Bubble's free plan. You need a paid plan (Starter or above) for API Workflows, which are required if you want server-side triggered MongoDB writes — such as a Bubble scheduled workflow that inserts a daily summary document or a Backend Workflow that receives a webhook from an external service and writes to MongoDB.

What is the best way to paginate through large MongoDB collections in Bubble?

Use `limit` and `skip` parameters in your FindDocuments call. Create a custom state in Bubble named `currentPage` initialized to `1`. Bind the `skip` body parameter to `(currentPage - 1) × limit` (e.g., page 1 = skip 0, page 2 = skip 25). Add 'Previous' and 'Next' buttons that decrement and increment the `currentPage` state, which triggers the Repeating Group to re-fetch. This is offset-based pagination — simple for Bubble to implement, though it can be slightly inconsistent if documents are inserted while a user is paginating.

Can Bubble receive real-time updates from MongoDB when documents change?

Bubble's API Connector is request-response (pull), not push. For real-time reactions to MongoDB document changes, use MongoDB Atlas Triggers: in Atlas App Services, create a Database Trigger on your collection that fires on insert or update events and sends an HTTPS POST to a Bubble Backend Workflow URL. This requires a paid Bubble plan for the Backend Workflow feature. The Atlas Trigger pushes the changed document to Bubble, which can then update a database record or send a notification.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.