Designing a Deta Space App with Deta Base as the Persistent Store
Learn how to scope a Deta Space app to use Deta Base as its only persistent store, covering requirements, trust boundaries, operational checks, and failure modes.
21 Jul 2026, 09:04 UTC

Requirements
Before choosing Deta Base as the store for a Deta Space app, confirm that the workload fits its strengths: per‑user settings, small document collections, and low‑to‑moderate write traffic. If you need relational joins, multi‑item ACID transactions, or sustained writes above a few hundred per second, plan for an external database instead.
Smallest Suitable Design
The minimal architecture is a single‑process web application that runs inside a Deta Space instance and talks directly to Deta Base via the official SDK. No separate database server, no caching layer, and no shared state between instances.
Example handler (Node.js)
const deta = require('deta');
const base = deta.base(process.env.DETA_BASE_NAME); // DETA_BASE_NAME set in Space env
// GET /settings – return user‑specific settings
async function getSettings(req, res) {
try {
const item = await base.get('settings'); // key is fixed per user instance
if (!item) {
return res.status(404).json({error: 'not found'});
}
res.json(item.value);
} catch (err) {
// treat as transient; retry logic lives in middleware
res.status(502).json({error: 'base unavailable'});
}
}
// POST /settings – replace settings
async function putSettings(req, res) {
try {
await base.put({value: req.body}, 'settings');
res.status(204).end();
} catch (err) {
res.status(502).json({error: 'base unavailable'});
}
}
Place the file in the Space’s src/ folder, expose the functions through your framework’s router, and add a simple health endpoint that returns 200 OK when the process is alive.
Trust and Data Boundaries
- Trust boundary: The Space runtime injects the project key and any secret values as environment variables (DETA_PROJECT_KEY, DETA_BASE_NAME, etc.). Server‑side code can read these safely, but the values must never be sent to the browser. Treat any data received from client‑side JavaScript as untrusted and validate it before passing it to Base.
- Data boundary: Because each Space user receives an isolated instance, there is no cross‑tenant isolation problem inside the app. Any call you make to a third‑party API leaves the Space trust boundary; keep such calls to a minimum, use HTTPS, and consider encrypting sensitive payloads before transmission.
Operational Checks
- Health endpoint – expose GET /health that returns {status: 'ok'} and logs a request ID.
- Structured logging – include a unique request ID (e.g., from req.headers['x-request-id']) in every log line to aid tracing.
- Periodic backup – since Deta Base lacks built‑in point‑in‑time recovery, run a cron‑like job (or a manual script) that exports all items to a JSON file and stores it in Deta Drive or an external bucket.
- Monitor limits – watch the Base item count and storage size shown in the Space dashboard; set alerts when usage exceeds 80 % of the quota to avoid sudden throttling.
Verification Steps
- Deploy a minimal Space app that writes a test item to Base, reads it back, and confirms the value matches.
- Restart the instance (e.g., deta update --force) and verify the item is still present, proving no reliance on in‑memory state.
- Simulate a Base error by temporarily setting an invalid DETA_BASE_NAME and observe the app returning a 502 with the fallback message.
- Run a backup script: deta base fetch > backup.json and then restore into a fresh Base with deta base put < backup.json (adjust for SDK). Compare item counts.
Failure Modes and Mitigations
- Base unavailability or rate limiting: The SDK throws an error; implement exponential backoff with a maximum of three retries, then degrade to read‑only mode or return a friendly error to the user.
- Cold‑start latency: Idle Space instances are stopped after a few minutes; the first request may suffer a few hundred milliseconds of latency. Keep the app lightweight and consider a lightweight ping (e.g., from a monitoring service) to keep the instance warm if latency is critical.
- Silent data loss: If you skip backups and the Base instance experiences corruption (rare but possible), data may be lost. Verify backups by restoring them into a fresh Base collection and checking item counts.
- Stateful in‑memory assumptions: Do not rely on in‑memory caches across requests; each request should read the latest value from Base to survive instance restarts.
When to Reconsider the Design
If any of the following conditions appear, move to a more traditional database:
- Need for relational queries, joins, or complex indexing.
- Requirement for multi‑item transactions with strong consistency.
- Expected write throughput exceeding the Base quota (currently a few hundred writes per second per instance, subject to change).
- Desire for point‑in‑time recovery or built‑in replication.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.