Skip to main content Scroll Top
Back to insights
Adobe App Builder July 22, 2026 11 mins read

Adobe App Builder Database Configuration: How It Actually Works (Copy)

Adobe App Builder Database Storage is a MongoDB-compatible document database (built on Amazon DocumentDB) that gives structured, queryable storage for App Builder apps. It covers provisioning, IMS auth, CRUD, indexing, and the two errors almost everyone hits first.

Fast answer: Adobe App Builder Database is a MongoDB-compatible document database, built on Amazon DocumentDB, that gives your App Builder Runtime Actions structured storage with CRUD operations, filtering, sorting, indexing, and aggregation the kind of querying State Storage and File Storage were never meant to handle.

If you’re building anything on top of Adobe Commerce or App Builder that touches user profiles, product catalogs, orders, or reporting, this is the storage layer you’ll eventually need to understand properly. Here’s the full picture, including the two errors that trip up almost everyone the first time they try to write to it.

The Problem With Using State or File Storage for Structured Data

Here’s the situation most developers land in. You start an App Builder project, you need somewhere to keep data, and State Storage is right there, already wired up, zero provisioning steps. So you use it. It works fine for a while session flags, cached tokens, small counters.

Then the app grows. You need to filter users by role. You need to join order records with customer records. You need a report grouped by status. And State Storage, which is a key-value store, just can’t do any of that. File Storage can’t either it’s built for storing files, not for querying structured data. At that point you’re either bolting on an external database (extra hosting, extra auth, extra cost) or you’re looking at what Adobe already built for exactly this problem.

What Is Adobe App Builder Database Storage, Really?

Adobe App Builder Database Storage is a MongoDB-compatible document database powered by Amazon DocumentDB under the hood. Instead of rows and columns, it stores information as JSON-like documents inside collections the same mental model as MongoDB, which is probably the biggest reason developers pick it up fast.

A document looks like this:

{ "_id": "1001", "name": "John Doe", "email": "[email protected]", "role": "Admin" }

That document lives inside a collection, which is the App Builder Database equivalent of a table in a SQL system. The database supports:

  • CRUD operations
  • Rich filtering
  • Sorting
  • Aggregation
  • Indexing
  • Schema validation
  • Geospatial queries

That feature list is what separates it from State and File Storage. It’s built for applications with data models that actually have shape and relationships, not just flat key-value pairs.

When Database Storage Makes Sense

Use App Builder Database when your application needs:

  • User profiles
  • Product catalogs
  • Orders
  • Customer records
  • Analytics
  • Search functionality
  • Reporting
  • Relationships between entities

And skip it for:

  • Temporary session data
  • Cached API responses
  • Large media files

Adobe’s own guidance points to State Storage or File Storage for those three cases, and honestly, that’s the right call Database Storage adds provisioning overhead and connection management that temporary data doesn’t need.

How Database Storage Works, Step by Step

Every Runtime Action that touches the database follows the same chain: it fires, generates an IMS Access Token, initializes aio-lib-db, opens a connection, picks a collection, does its CRUD work, then closes the connection. That authenticated-connection-per-action pattern is the whole security model, and it’s worth understanding before you write a single line of code, because it explains most of the errors you’ll hit later.

Step 1: Provision the Database

Database Storage isn’t switched on by default the way State Storage is. You provision it explicitly.

Install the library first:

npm install @adobe/aio-lib-db

Then provision:

aio app db provision

This creates the actual database resources tied to your App Builder workspace. Skip this step and every downstream call fails with a “database not found” error we’ll come back to that in the mistakes section.

Step 2: Configure Authentication With an IMS Token

App Builder Database uses IMS Access Tokens for auth, generated inside your Runtime Action:

const { generateAccessToken } = require("@adobe/aio-sdk").Core.AuthClient;const token = await generateAccessToken(params);

No username, no password hardcoded anywhere. The token authorizes that specific Runtime Action to talk to the database, which is a cleaner security posture than most self-hosted database setups get by default.

Step 3: Initialize the Database Library

const libDb = require("@adobe/aio-lib-db");const db = await libDb.init({ token: token.access_token,});

If your database sits in a different region, say so explicitly:

const db = await libDb.init({ token: token.access_token, region: "emea",});

Supported regions: amer, emea, apac.

A more complete, production-shaped version of this initialization the kind we’d actually ship in a client’s codebase looks like this:

import { createRequire } from "node:module";import { Core } from "@adobe/aio-sdk";import { getAdobeAccessToken } from "../lib/adobe-auth.js";const require = createRequire(import.meta.url);const { init } = require("@adobe/aio-lib-db");let dbInstance = null;export async function getDBClient(params = {}) { // Return existing connection if already initialized if (dbInstance) { return dbInstance; } const logger = Core.Logger("db-client"); // Generate Adobe IMS Access Token const token = await getAdobeAccessToken(params); // Initialize Database const db = await init({ token, region: params.AIO_DB_REGION || "amer", }); // Create Database Connection const client = await db.connect(); // Access collections const usersCollection = client.collection("users"); const productsCollection = client.collection("products"); const ordersCollection = client.collection("orders"); const auditLogsCollection = client.collection("audit_logs"); dbInstance = { db, client, usersCollection, productsCollection, ordersCollection, auditLogsCollection, }; logger.info("Database initialized successfully."); return dbInstance;}

That dbInstance caching pattern matters more than it looks. Re-initializing the connection on every invocation is one of the quiet ways teams burn through their request limits without realizing it.

Step 4: Create the Database Connection

const client = await db.connect();

Think of this client as the bridge between your Runtime Action and the actual database.

Step 5: Access Collections

const database = client.db();const users = database.collection("users");

A collection behaves like a SQL table, minus the rigid schema. Every operation from here happens against this collection reference.

Steps 6-9: Insert, Read, Update, Delete

This is where the Adobe App Builder CRUD operations actually happen, and the API will feel immediately familiar if you’ve touched MongoDB before.

Insert one document:

await users.insertOne({ name: "Alice", email: "[email protected]", role: "Developer" });

Insert multiple:

await users.insertMany([ { name: "John" }, { name: "Mary" }]);

Find all users:

const result = await users.find({}).toArray();

Find one:

const user = await users.findOne({ email: "[email protected]" });

Filter:

const admins = await users.find({ role: "Admin" }).toArray();

Update one:

await users.updateOne( { email: "[email protected]" }, { $set: { role: "Manager" } });

Delete one:

await users.deleteOne({ email: "[email protected]" });

Delete many:

await users.deleteMany({ role: "Guest" });

Step 10: Close the Connection

await client.close();

Always do this. Skipping it is how connections leak and applications get slower the longer they run.

What’s Actually Happening Behind the Scenes

When a Runtime Action fires, here’s the real sequence: the action starts, an IMS Access Token gets generated, aio-lib-db initializes the client, a secure connection is established, the database operation runs, results come back, and the connection closes. Every single one of those steps is authenticated there’s no point in that chain where credentials sit exposed in your code, which is the entire reason Adobe built it this way instead of letting you pass a connection string directly.

Best Practices for Collections, Indexing, and Aggregation

Organize With Collections

Collections group related documents think users, products, orders, payments, logs. Each one can hold millions of documents without you needing to think about it differently than a few hundred.

Without an index, the database scans every document to find a match. With one, it goes straight to the result. For any field you query often email, status, order ID index it:

await users.createIndex({ email: 1 });

We’ve watched a single missing index turn a “why is this endpoint slow” ticket into a two-hour investigation that ended with one line of code.

Use Aggregation for Reporting

Aggregation runs the processing server-side instead of pulling everything back to your Runtime Action and crunching it there:

const report = await orders.aggregate([ { $group: { _id: "$status", total: { $sum: 1 } } }]).toArray();

This is the pattern behind sales reports, dashboard analytics, revenue summaries, and category counts anything where you’d otherwise be writing a loop in application code that the database can do faster natively.

Comparison: Which App Builder Storage Fits Your Use Case

Storage Type Best For Querying Setup Required
Database Storage Structured, relational data Rich filtering, aggregation, indexing Manual provisioning
State Storage Session data, flags, counters Key lookup only None
File Storage Media, exports, large blobs None None

Other Habits Worth Building In

  • Close connections properly, wrapped in try/finally so a failed operation doesn’t leave the connection open:
try { // operations} finally { await client.close();}
  • Fetch only the fields you need with projections, instead of pulling full documents you’ll trim in application code:
collection.find({}).project({ name: 1, email: 1 });
  • Use cursors for large datasets instead of .toArray(), which loads everything into memory at once:
for await (const doc of collection.find()) { // process doc}

It’s worth keeping the platform limits in mind while you design your data model:

Feature Limit
Max document size 16 MB
Collections 1000
Requests 20,000 per minute
Monthly bandwidth 10 TB

None of these are limits you’ll hit with a typical customer-management or catalog-sync app. They matter more if you’re logging high-frequency events or storing large embedded objects inside a single document.

Common Mistakes We See Teams Make

1. Trying to write before adding the App Builder Data Services API scope. This is the single most common failure we’ve walked clients through. You’ll see:

Failed to save views... 403 Forbidden Missing required scope: adobeio.abdata.write

It happens because the App Builder project doesn’t have App Builder Data Services added yet, so the generated access token never picks up the adobeio.abdata.write scope. Fix it in the Adobe Developer Console: open your workspace, add App Builder Data Services, refresh the credentials if needed, then redeploy with aio app deploy. The next generated token will carry the write scope and the error disappears.

2. Assuming the database exists because the code compiles. Database Storage isn’t provisioned automatically the way State Storage is. If you skip aio app db provision, you’ll get “Database not found” or “Collection does not exist” the first time you try to use it not at build time, only at runtime. Run:

aio app db provision --region amer

before you ever try to connect.

3. Reconnecting on every single invocation. We mentioned the caching pattern earlier for a reason teams that call db.connect() fresh on every action invocation burn through request quota faster than they expect, and it’s an easy fix once you know to look for it.

4. Skipping indexes until performance becomes a visible problem. Nobody adds an index proactively on a field they “probably won’t search much.” Then three months later that field is exactly what a dashboard filters on, and every load takes a noticeable beat longer than it should.

5. Pulling entire collections into memory with .toArray() on datasets that keep growing. It works fine at 500 documents. It gets uncomfortable at 50,000. Cursors exist precisely for this.

FAQ

What is Adobe App Builder Database?

It’s a MongoDB-compatible, document-based database storage option inside Adobe App Builder, running on Amazon DocumentDB. It stores data as JSON-like documents in collections and supports CRUD operations, filtering, indexing, and aggregation.

How do I provision a database in Adobe App Builder?

Install @adobe/aio-lib-db, then run aio app db provision from your App Builder project. You can specify a region with aio app db provision –region amer.

Is Adobe App Builder Database free to use?

Pricing depends on your Adobe App Builder entitlement and usage against the platform’s request and bandwidth limits. Check your Adobe Developer Console workspace or your Adobe account rep for the specifics that apply to your plan.

What is the difference between Database Storage and State Storage in App Builder?

State Storage is key-value only, requires no provisioning, and suits temporary data like session flags. Database Storage is a full document database with querying, indexing, and relationships, and it does need to be provisioned before use.

Conclusion

The pattern is consistent across every App Builder Database project we’ve touched: teams start on State Storage because it’s already there, hit a wall once their data needs structure, and then either provision Database Storage properly or spend more time and money standing up something external that does the same job worse. If your App Builder app is going to outgrow key-value pairs, it’s worth setting up Database Storage from day one rather than migrating under pressure later.

Get Help With Your App Builder Build

If you’re mid-integration and hitting the scope error, or you’re deciding whether Database Storage fits your Adobe Commerce project at all, we’ve covered related setup work in our guide to subscribing webhooks in Adobe Commerce as a Cloud Service, which uses App Builder as one of its event destinations. If you’re also weighing a platform move, our ecommerce replatforming guide walks through the bigger decision. For teams running Magento 2, our Magento 2 Hyva setup guide and Magento 1 to Magento 2 migration guide cover adjacent groundwork many of our App Builder clients need first. You can also see how our team approaches Adobe Commerce development directly.

Ethnic Infotech builds and maintains App Builder integrations, custom Adobe Commerce modules, and headless storefronts for international brands. If you’re stuck on a Database Storage setup or planning a bigger App Builder build, talk to our team.

Need a strong digital partner?

Planning your next product, platform, or growth move?

Ethnic Infotech helps teams shape scalable software, sharper customer experiences, and content systems that support real business growth.

Talk to our team Browse more articles

Comments (3)

Leave a comment

More insights

Keep reading

Privacy Preferences
When you visit our website, it may store information through your browser from specific services, usually in form of cookies. Here you can change your privacy preferences. Please note that blocking some types of cookies may impact your experience on our website and the services we offer.