Skip to content
Scava Docs Join the waitlist

Scava opens soon. These docs describe how it works at launch. Join the waitlist

All chapters

Data

A database for an app your agent built - scava.db

An app on Scava gets a shared database without any setup. The app calls scava.db('name') and stores entries that everyone with access to the app sees. There is no server to run, no connection string and no schema. The agent that builds the app needs nothing more than the four calls below.

The four calls #

const db = scava.db('vacation');          // a collection; it exists once you write to it

const entries = await db.list();           // the entries this person may read, oldest first
const entry = await db.add({ from: '2026-12-22', to: '2026-12-31' });
await db.update(entry.id, { to: '2027-01-02' });
await db.remove(entry.id);

Every entry comes back in this shape:

{
  "id": "k3x9...",
  "data": { "from": "2026-12-22", "to": "2026-12-31" },
  "created_by": "anna@company.com",
  "created_at": 1790000000000,
  "updated_by": null,
  "updated_at": null
}

created_by and updated_by are email addresses. The timestamps are milliseconds since 1970, as Date.now() returns them. The rules in scava.json use created_by to decide what "own" means; see Permission rules.

A complete small app #

Save this as index.html in a folder and publish it. It is a working vacation list.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Team vacation</title>
</head>
<body>
  <h1>Team vacation</h1>
  <form id="form">
    <input id="from" type="date" required>
    <input id="to" type="date" required>
    <button>Add</button>
  </form>
  <ul id="list"></ul>
  <script>
    const vacation = scava.db('vacation');
    const list = document.getElementById('list');

    async function show() {
      const entries = await vacation.list();
      list.textContent = '';
      for (const e of entries) {
        const li = document.createElement('li');
        li.textContent = e.created_by + ': ' + e.data.from + ' to ' + e.data.to;
        list.append(li);
      }
    }

    document.getElementById('form').addEventListener('submit', async (event) => {
      event.preventDefault();
      await vacation.add({
        from: document.getElementById('from').value,
        to: document.getElementById('to').value,
      });
      event.target.reset();
      show();
    });

    show();
  </script>
</body>
</html>

The Scava script is loaded before your own scripts, so scava is always there. Show stored text with textContent, as above, or pass it through scava.escape(text) when you build HTML.

Many entries: paging #

One list() call returns one page. When there are more entries, the result has a next value. Pass it back as after:

let page = await db.list({ limit: 500 });
const all = [...page];
while (page.next) {
  page = await db.list({ limit: 500, after: page.next });
  all.push(...page);
}

db.list({ order: 'newest' }) starts with the newest entry; the default is 'oldest'. next is null on the last page.

There is no query language. To find entries, list them and filter in the page, or keep separate collections for separate questions.

Who sees what #

Everyone with access to the app sees the same data, unless the rules in scava.json say otherwise. By default every person reads all entries and changes only the entries they created; the owner can do everything. The rules are enforced on Scava's server, so a changed page or a hand-made request cannot get around them. See Permission rules.

What is not accepted #

Scava cleans what is stored, so that an entry can never become code in another person's browser.

Limits #

WhatLimit
Size of one entry64 KB
Entries per app1,000,000
Data per app2 GB
Changes per person and app300 in 10 minutes
Storage per accountFiles and entries of all your apps together count against the storage of your plan: Starter 10 GB, Team 50 GB, Business 250 GB

When the storage of the plan or a limit of the app is used up, further writes fail with "This app has reached its storage limit." More limits are in Limits.

One database per app #

Each app has a database of its own. An app cannot read the entries of another app, and one app cannot fill the space of another. The data lives in the EU unless the owner chose the US for new apps; see Data location.

Export and deletion #

The owner of an app can download everything the app holds from the app page: the files of the live version, every collection as a JSON file, and every uploaded file, in one ZIP. The download needs a sign-in from the last 12 hours, works only in the browser, and is limited to 10 per app and hour. Deleting the app deletes its entries and files.

Server code #

Server code reads and writes the same collections with env.SCAVA.db('vacation'), which also offers get(id). See Server code.