# Databases

Every database you create is a separate SQLite database on the edge — two databases never share a file or a table. Engine "sqlite" is the one available today; Postgres, MySQL and Redis answer 501 until they exist.

There is no host and port: every query is a `POST https://harakumo.com/api/databases/:id` with an API key. Keep the key on your server.

## Connect from your app

1. Create the database (dashboard, CLI or `POST /api/projects/:id/databases { name }`) and note its id. The database page's Connect tab shows the endpoint, the id and snippets with your real values.
2. Create an API key limited to the project (Settings → API access; full access, Project set). Queries need full access, even for SELECT.
3. Put the key and the database id in the project's environment variables (for example HARAKUMO_API_KEY and NOTES_DB_ID) and redeploy.
4. Query from server code: the SDK, fetch or curl.

**fetch**

```js
const res = await fetch('https://harakumo.com/api/databases/' + process.env.NOTES_DB_ID, {
  method: 'POST',
  headers: { authorization: 'Bearer ' + process.env.HARAKUMO_API_KEY, 'content-type': 'application/json' },
  body: JSON.stringify({ sql: 'SELECT * FROM notes WHERE id = ?', params: [42] }),
});
const { results, meta } = await res.json();   // results: rows of the last statement
```

**curl**

```bash
curl -X POST https://harakumo.com/api/databases/5 \
  -H "Authorization: Bearer $HARAKUMO_API_KEY" -H "content-type: application/json" \
  -d '{ "sql": "SELECT count(*) AS n FROM notes" }'
```

## Responses

- A single request answers `{ results, statements, meta }`. SQL holding several statements runs them in order; `results` holds the last statement's rows and `statements` how many ran.
- `meta` has the rows read and written, changes and last_row_id from the database.
- Use `?` placeholders with `params` for every value — never build SQL by joining strings.

## Batch

Send up to 100 statements, each with its own params, in one request. It counts once toward the workspace rate limit, so batching is the way to do bulk work. Do not rely on a failing statement rolling back the earlier ones in the same batch until that behavior is confirmed; design writes to be safe to retry.

**Batch**

```bash
curl -X POST https://harakumo.com/api/databases/5 \
  -H "Authorization: Bearer $HARAKUMO_API_KEY" -H "content-type: application/json" \
  -d '{ "batch": [
        { "sql": "INSERT INTO notes (body) VALUES (?)", "params": ["first"] },
        { "sql": "INSERT INTO notes (body) VALUES (?)", "params": ["second"] },
        { "sql": "SELECT count(*) AS n FROM notes" } ] }'
# → { "batch": [ { "results": [], "meta": {…} }, …, { "results": [{ "n": 2 }], "meta": {…} } ] }
```

## Export

`POST /api/databases/:id/export` starts an export and answers `{ status: "active", bookmark }` while it runs; call again with the bookmark until it answers `{ status: "complete", download }`. `GET /api/databases/:id/export?bookmark=…` returns the .sql file (schema and data), which any SQLite tool can load. The Connect tab has an Export button.

There is no point-in-time restore or import through Harakumo yet. Export regularly if the data matters, and treat delete as permanent.

## Limits

| Limit | Value |
| --- | --- |
| Size of one database | 10 GB |
| One row or value | 2 MB |
| One SQL statement | 100 KB |
| Bound parameters per statement | 100 |
| Time per query | 30 seconds |
| Columns per table | 100 |
| Statements per batch | 100 |
| Query requests per workspace | 600 per 5 minutes |
| Databases per plan | 1 hobby, 10 pro, 100 enterprise |

## Errors

| Status | Meaning |
| --- | --- |
| 400 | A SQL mistake; the message is the database's own. |
| 409 | The database is not available (its create failed, or it was never created). A failed create shows the reason; retry with `PATCH { "action": "retry" }` — it does not count against the plan. |
| 410 | The database no longer exists on the edge. |
| 429 | The workspace rate limit or the database service is throttling. Wait Retry-After seconds, and batch. |
| 502 / 503 | A platform problem. Retry shortly. |

## How it scales

Each database has one writer and stops at 10 GB, and every query is an HTTPS call through Harakumo, capped at 600 requests per 5 minutes per workspace. That suits development, internal tools and low-traffic apps. For more: batch statements, cache reads in your app, and split data across several databases (per customer, per region). Direct connections from your functions and apps, read replicas and a Postgres engine for single datasets over 10 GB are planned.

## Moving from MongoDB

@harakumo/docdb keeps the MongoDB and Mongoose call shapes (find, updateOne, populate, bulkWrite …) and stores documents as JSON in a Harakumo database, so an app moves without rewriting every query. It is in preview and not yet published to npm; ask support for access.

## Reference

**SDK**

```js
const { database } = await hk.databases.create(project.id, { name: 'app', engine: 'sqlite' });
const { results } = await hk.databases.query(database.id, 'SELECT * FROM users WHERE id = ?', [42]);
// Batches and export are REST calls (below); the SDK sends single statements.
```

**CLI**

```bash
harakumo db 12                                # list a project's databases
harakumo db create 12 app --engine sqlite
harakumo db query 5 "select count(*) from users"
```

**REST**

```http
POST   /api/projects/:id/databases     { "name": "app", "engine"?: "sqlite" }
GET    /api/databases/:id              # the database, its endpoint and limits
POST   /api/databases/:id              { "sql": "SELECT * FROM users WHERE id = ?", "params": [42] }
POST   /api/databases/:id              { "batch": [{ "sql": "…", "params": [] }, …] }   # up to 100
PATCH  /api/databases/:id              { "action": "retry" }     # re-run a failed create
POST   /api/databases/:id/export       { "bookmark"? }            → { status, bookmark, download? }
GET    /api/databases/:id/export?bookmark=…                      # the .sql file
DELETE /api/databases/:id              # permanent
```
