All posts
Developers·7 min read

Using the m77 database: collections, filters and per-user data

Every builder77 app ships with a built-in database. Here's how collections, filters, sorting and per-user records work — and how to keep private data private.

77
The builder77 team
builder77.com

Most of the time you'll never touch the database directly — you describe your app, and builder77 writes the code that stores and reads data. But knowing how it works helps you write better prompts, debug faster and make good decisions about privacy. Here's a tour of m77.db.

Collections and records

Data lives in collections — named groups of records like tasks, bookings or posts. There's no schema to define: a collection is created the first time you write to it, and each record is a plain object with whatever fields you give it.

js
const task = await m77.db.create('tasks', { title: 'Write launch post', done: false });
// -> { id, title, done, createdAt, updatedAt, ownerId }

builder77 adds id, createdAt, updatedAt and ownerId automatically. ownerId is set to the signed-in app user when there is one, which becomes important for permissions below.

Reading data: list, get and count

js
const open = await m77.db.list('tasks', {
  where: { done: false },   // exact-match filter
  sort: '-createdAt',       // '-' = descending
  limit: 50                 // up to 500
});

const one = await m77.db.get('tasks', id);          // record or null
const doneCount = await m77.db.count('tasks', { where: { done: true } });

where matches fields exactly, which covers most app needs: status filters, categories, a parent ID for related records. For search-as-you-type over a modest list, it's common to load the records and filter in the browser.

Updating and deleting

js
await m77.db.update('tasks', id, { done: true });   // shallow merge
await m77.db.remove('tasks', id);

update merges the fields you pass into the existing record, so you only need to send what changed.

Per-user data with mine: true

For apps where each person has their own data — journals, budgets, habit trackers — combine m77.auth with the mine option. When a user is signed in, mine: true returns only the records they created.

js
await m77.auth.signIn({ email, password });

const myEntries = await m77.db.list('entries', { mine: true, sort: '-createdAt' });

There's a second layer of protection built in: a record that was created by a signed-in user can only be updated or deleted by that same user. Even if someone crafts a request by hand, the API rejects edits to records they don't own.

Public vs. private data: a quick guide

  • Public content (menu items, blog posts, product listings): no sign-in needed to read. Ask builder77 to seed them, or add an admin screen to manage them, and edit them anytime in the Data tab.
  • Submissions (contact forms, waitlists, bookings): anyone can create them; you read them in the Data tab.
  • Personal data (notes, health logs, finances): require sign-in and always query with mine: true.

One rule of thumb: anything in your app's front-end code is visible to visitors, and lists without mine: true can be read by anyone who has the app link. If data is personal, put it behind sign-in and mine. If the whole app is just for you or your team, turn on private app in Settings.

The Data tab

In the builder, the Data tab lets you browse every collection, edit or delete records, see your app users and review uploaded files. It's the quickest way to fix a typo in content, clean up test entries, or check that a form is saving what you expect.

Same data from Flutter and other clients

The web SDK is a thin wrapper around a REST API, which is also what Flutter exports use. That means any client can read and write the same collections:

http
GET  /api/runtime/<projectId>/db/tasks?where={"done":false}&sort=-createdAt&limit=100
POST /api/runtime/<projectId>/db/tasks   { "data": { "title": "Hi" } }
Authorization: Bearer <appUserToken>   (optional, from /auth/signin)

App user tokens are scoped to a single project, so a token from one app can't be used against another. Database reads and writes don't use credits — build as data-heavy an app as you like.

Prompting for data

You can steer all of this in plain language: "store expenses with amount, category and date; each user sees only their own", or "add a status field to bookings and a filter for pending ones". The AI knows the SDK, so describing the data model is usually all it takes.

Ready to build it?

Describe your idea and get a working first version in about a minute. Free to start, no credit card required.