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
- 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. - Create an API key limited to the project (Settings → API access; full access, Project set). Queries need full access, even for SELECT.
- Put the key and the database id in the project's environment variables (for example HARAKUMO_API_KEY and NOTES_DB_ID) and redeploy.
- Query from server code: the SDK, fetch or curl.
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 statementcurl -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;resultsholds the last statement's rows andstatementshow many ran. metahas the rows read and written, changes and last_row_id from the database.- Use
?placeholders withparamsfor 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.
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 |
| Database storage per plan (all databases together) | 0.5 GB hobby, 10 GB pro, 100 GB enterprise, measured daily; on Hobby, across all your free workspaces |
On Hobby, database writes that add data (reads and deletes still work) are refused once the plan's database storage allowance is used up (402 usage_limit). On Pro and Enterprise, use past it is charged daily from the Balance at $1.00 per GB a month, and database writes that add data pause (402 usage_paused) only while a charge cannot be paid.
Errors
| Status | Meaning |
|---|---|
| 400 | A SQL mistake; the message is the database's own. |
| 402 | The plan's database storage is used up, so statements that add data (INSERT, UPDATE, REPLACE, UPSERT, CREATE, ALTER) are held: usage_limit on Hobby, usage_paused on a paid plan that cannot pay for more. Reads, DELETE and DROP still run, so you can clean up (a DELETE is held too when the database has triggers, since a trigger can add data when rows are deleted: drop the triggers first), but a batch that contains any statement that adds data is held as a whole: send reads and deletes in a batch of their own. A word inside quotes, a quoted name or a comment does not count. The size is measured again daily, so room you free counts from the next measurement. |
| 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
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.harakumo db 12 # list a project's databases
harakumo db create 12 app --engine sqlite
harakumo db query 5 "select count(*) from users"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