Browse the docs

Reference

Limits

Every limit fuast enforces, with its default, the exact error, and what to change. Handler and database budgets, actions, app state, daily quotas, storage, email, server env, deploys, unclaimed previews, rate limits, and how to check usage.

Every app runs with resource limits. This page lists each one, its default, the error you get when you cross it, and what to change in your capsule. Limits apply the same way in fuast dev and on hosted apps, except where a row says otherwise. Self-hosted platforms can change some defaults with environment variables, listed at the end.

Handler limits

These apply to every query, mutation, action, endpoint, and schedule call. Crossing one fails the call, and a mutation, writable endpoint, or schedule rolls back its whole transaction.

Limit Default Error What to do
Rows returned 1000 collect() exceeded the 1000 row return limit. Use paginate(). for one read, Database rowsReturned limit exceeded (1000). across reads paginate(), or take(n) with a small n.
Rows read 5000 Database rowsRead limit exceeded (5000). Add an index that matches the filter so the scan stops early. count() spends this budget too.
Bytes read 4 MiB Database bytesRead limit exceeded (4194304). Return fewer rows. Move large text to storage.
Direct get calls 1000 Database directGets limit exceeded (1000). Replace per-row get loops with one indexed query.
Index scans 100 Database scanCalls limit exceeded (100). Fold repeated queries into one range.
Writes 1000 Database writes limit exceeded (1000). Split the work across mutations or schedule runs.
Field value size 64 KiB Value for <table>.<field> exceeds 65536 bytes. Store the payload with storage and keep the key. Any value within this limit can be indexed.
take(n) 0 to 1000 take count must be an integer between 0 and 1000. Paginate instead.
Page size 1 to 1000 pagination numItems must be an integer between 1 and 1000. Use 10 to 100 for UI lists.
Database time 5000 ms per call Database transaction timed out. Do less per call. Keep fetch calls short.
CPU time 5000 ms Handler exceeded the 5000ms CPU time limit. Avoid heavy loops. Precompute during writes.
Wall-clock time 10 s Handler exceeded the 10000ms wall-clock limit. Same as above. Slow fetch calls count.
Memory 128 MB per isolate The call fails. Do not build huge arrays or strings.
Waiting for the write lock 30 s The app is busy with other writes. Retry shortly. (code busy) Keep mutations short so they do not queue behind each other.

Hosted CPU, wall-clock, memory, and write-lock limits come from the isolate runtime. fuast dev runs handlers in Bun workers. It enforces the database budgets, database time, the 10 s wall-clock limit, and the action limits, but not the separate CPU and memory limits, so a CPU-heavy handler that works locally can still fail once deployed.

Outbound fetch

Limit Default Error
Timeout per request 10 s fetch timed out after 10000ms. (code timeout)
Request body 5 MiB fetch request body exceeds 5242880 bytes. (code too_large)
Response body 5 MiB fetch response body exceeds 5242880 bytes. (code too_large)
Redirects 5 fetch: too many redirects (max 5).
Private addresses Blocked Requests to loopback, private, and link-local addresses fail with code ssrf.

Fetch time also counts toward the handler's wall-clock limit and holds the app's write lock in a mutation.

Action limits

Limit Default Error
Arguments 16 KiB Action arguments exceed 16384 bytes.
Result 48 KiB Action result exceeds 49152 bytes.
Runtime 5000 ms Action exceeded 5000ms.

Pass an id and read the data inside the action instead of passing the data. Return only the fields the client needs. A failed action does not undo its outbound effects, so do not assume it is safe to retry.

Endpoint and connection limits

Limit Default Behavior
Endpoint request body 5 MiB 413 with Request body is too large (5 MiB max). (code too_large)
WebSocket message 1 MiB The connection closes. Send large data through storage.
Mutations and actions in flight per connection 4 Later calls queue in order.
Queued calls per connection 1000 Further calls fail. Batch into one mutation.

App limits

Limit Default Error What to do
Stored rows 100000 State row limit exceeded (100000). Delete rows you no longer need. Keep summaries instead of raw events.
Stored row bytes 64 MiB State byte limit exceeded (67108864). Shorten values. Move blobs to storage.
Requests per UTC day 100000 HTTP 429, bucket: "requests" Cut round trips. One live subscription beats polling.
Mutations per UTC day 20000 HTTP 429, bucket: "mutations" Batch writes into one mutation. Actions and writable endpoints count here too.
Emails per UTC day 100 fuast_quota_exceeded, bucket: "email" Send a digest from a schedule instead of one email per event.
Pending jobs 10000 Pending job limit exceeded (10000). Cancel jobs or let them finish first. Batch work into fewer jobs, or cancel stale ones (fuast jobs cancel). See jobs.
Jobs scheduled per handler call 1000 Job limit exceeded: at most 1000 jobs per handler call. Schedule one job that fans out in batches.
Job arguments 64 KiB Job arguments exceed 65536 bytes. Pass ids, not documents.
Log buffer 1000 entries or 256 KiB Oldest entries are dropped. No error. Log less, or read logs sooner.
Log entry size 16 KiB Long entries are cut and data becomes { truncated: true }. Log a summary, not the whole object.
Favicon 64 KiB, .svg or .ico Build error: favicon <path> is <n> bytes; the limit is 65536 bytes (64 KiB). Use a smaller icon.

Stored row limits fail the write that crosses them. They have no reset: delete data to get under them again.

Email limits

Limit Default Error
Emails per app per UTC day 100 fuast_quota_exceeded, bucket: "email"
Recipients per call 1 ctx.email.send needs \to` as one email address.`
Subject 998 characters The email subject is too long.
Body (text + html) 256 KiB The email body is too large (256 KiB max).

fuast dev logs emails instead of sending them. See email.

Storage limits

Limit Default Error
File size 25 MiB 413, code: "too_large"
Stored per workspace 1 GiB 413, code: "quota_exceeded"
Blocked types Executables, HTML, JavaScript 415, code: "blocked_type"
Uploads per IP 60 per minute 429, code: "rate_limited"

See storage.

Team table limits

Limit Default Error
Row size 64 KiB of JSON A team table row can be at most 65536 bytes.
Rows per team table 10000 Team table <name> is full (10000 rows).
Rows added at once 1000 Add at most 1000 rows at once.
Table name 1 to 64 letters, digits, _, -, . Team table names use 1-64 letters, digits, ...

See teams.

Server env limits

Limit Default Notes
Key format [A-Za-z_][A-Za-z0-9_]*, at most 128 characters Enforced for keys set in the dashboard Env tab.
Value size 32 KiB Enforced for values set in the dashboard. Keep .env.fuast.server values under the same size.
Where it is readable ctx.env in handlers Never in client code, shared code, or at build time.

.env.fuast.server travels with the deploy, so it is limited to 1 MiB like any source file.

Deploy limits

Limit Default Error
Source files per deploy 1000 413, A deploy can have at most 1000 files.
Source bytes per deploy 20 MiB 413, Deploy source is <n> bytes; the limit is 20971520.
One source file (and .env.fuast.server) 1 MiB 413, <path> is <n> bytes; files can be at most 1048576 bytes.
Build time 120 s The deploy fails with a build error.
Macro imports (with { type: "macro" }) Not allowed 422, code macro_import
Deploys per IP 30 per minute 429, Too many deploys. Wait a minute.

Deploys upload source, not build output, so these limits are generous for a capsule. Large data belongs in storage or the database, not in source files.

Unclaimed previews

An app deployed without an account is an unclaimed preview until a person claims it. It runs with the limits below instead of the app limits above. Claiming lifts the quotas at once. Email, team tables, the member list, schedules, and jobs stay off after the claim until the owner trusts the app. See restricted apps.

Limit Default Error What to do
Lifetime 72 hours from the first deploy. Redeploys do not extend it. The preview stops serving and is deleted. Give the person the claim link.
New previews per client address 5 a day. Deleting a preview does not give one back. 429, code unclaimed_ip_limit Claim one, or run fuast login.
Redeploys of previews per client address 30 a day 429, code unclaimed_ip_limit Batch your changes. Check locally with fuast check and fuast dev first.
Deploy requests per client address, failed ones included 100 per 24 hours 429, code rate_limited Fix build errors locally with fuast check.
Previews on the platform at once 500 503, code unclaimed_capacity, with Retry-After Try later, or run fuast login and deploy to an account.
Source per deploy 200 files, 1 MiB 413, code too_large Keep data out of source files.
Stored rows 2000 State row limit exceeded (2000). Claim the app.
Stored row bytes 2 MiB State byte limit exceeded (2097152). Claim the app.
Stored files 2 MiB per preview An unclaimed preview can store 2097152 bytes. Claim this app to use your workspace's storage. Claim the app.
Requests per UTC day 2000 HTTP 429, bucket: "requests" Claim the app.
Mutations per UTC day 500 HTTP 429, bucket: "mutations" Claim the app.
Outbound fetch calls 10 per handler call, 100 per UTC day This unclaimed preview is out of outbound fetch calls: it gets 10 per handler call and 100 a day. Claim the app to lift the limit. (code fuast_quota_exceeded) Claim the app. A call sets its share of the day's budget aside when it starts and gives back what it did not use, so calls that overlap near the end of the budget may get fewer than 10.
Pending jobs 100 Pending job limit exceeded (100). … Jobs do not run until the claim anyway.
Emails 0 Claim this app to use email: ctx.email.send is off in an unclaimed preview. (code unclaimed) Claim the app, then trust it.
Team tables, workspace members Not available Claim this app to use team tables: …, Claim this app to use ctx.workspace: … (code unclaimed) Claim the app, then trust it.
Schedules and jobs Registered, not run No error. fuast inspect shows them. They start when the claimed app is trusted. Jobs queued before the claim are cancelled.
Reports before suspension 3 different client addresses The preview stops serving (403, code suspended, on deploy and claim). The platform's operator reviews it.

fuast inspect <preview-slug> --usage shows these limits beside the current counts, and the response of the deploy lists them under limits.

Rate limits

The platform limits some routes per client IP in a sliding window. Crossing one returns HTTP 429.

Route Limit
POST <app>/api/call 600 per minute
Storage uploads 60 per minute
Deploys 30 per minute
Sign-in 10 per minute
Sign-up 5 per minute
Password token login (fuast login --email) 10 per minute
fuast login browser approval start 10 per minute
fuast login approval polling 120 per minute
Resend verification email 3 per 10 minutes
Request access to a private app 5 per hour per app
Report an unclaimed preview 10 per hour
Claim an app (POST /api/claims/<token>/claim) 30 per minute

WebSocket calls from the app's own client are covered by the daily quotas, not by these per-minute limits.

Reading a quota error

Daily quota errors on HTTP routes return status 429 with this body:

{
  "code": "fuast_quota_exceeded",
  "error": "requests quota exceeded. Limit: 100000.",
  "bucket": "requests",
  "current": 100001,
  "limit": 100000,
  "resetAt": "2026-11-11T00:00:00.000Z",
  "retryAfterSeconds": 41230,
  "suggestion": "Retry after the reset, or reduce request frequency.",
  "command": "fuast inspect my-app --usage"
}

The response also carries Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Do not retry in a tight loop. Wait retryAfterSeconds.

Over the WebSocket, the error arrives as { op: "error", error, code: "fuast_quota_exceeded", quota: { ...same body } }. Mutation and action promises reject with an error whose code is fuast_quota_exceeded.

bucket Counts Resets
requests Queries, mutations, actions, endpoint calls, HTTP calls 00:00 UTC
mutations Mutations, actions, writable endpoint calls 00:00 UTC
email ctx.email.send calls 00:00 UTC

Owners and workspace admins can still read usage, logs, and data exports after an app runs out of quota. Those reads do not spend the app's budget.

Checking usage

fuast inspect my-app --usage          # hosted app, by slug
fuast inspect my-app --usage --json
fuast inspect --port 3000 --usage     # local

Usage shows stored rows and bytes and today's request, mutation, and email counts beside their limits. fuast dev counts the same way but never rejects on daily quotas. Handler, action, and stored-row limits do apply locally, so local testing catches them.

fuast inspect also prints per-read database metrics:

  read by_owner: returned=20 read=20 bytes=4096
  read by_creation: returned=50 read=4800 bytes=1900334 full-scan

returned, read, and bytes are the counters behind the handler limits. full-scan marks a read that walked by_creation on a large table without a range. It is the usual cause of a rowsRead failure: add an index that matches the filter. To see the metrics of one query with your own arguments, run it with fuast inspect --query. See test and debug.

Self-hosted overrides

Operators running their own platform can change these defaults. Every limit uses one variable family, FUAST_LIMIT_*, and the platform, the runtime, and fuast dev all read it the same way, so set the same values for every process (the platform sends the database budgets with each call, the runtime enforces the isolate limits). Values must be positive integers; anything else is ignored.

Variable Changes Default
FUAST_LIMIT_ROWS_RETURNED Rows returned per handler call 1000
FUAST_LIMIT_ROWS_READ Rows read per handler call 5000
FUAST_LIMIT_BYTES_READ Bytes read per handler call 4194304
FUAST_LIMIT_DIRECT_GETS Direct get calls per handler call 1000
FUAST_LIMIT_SCAN_CALLS Index scans per handler call 100
FUAST_LIMIT_WRITES Writes per handler call 1000
FUAST_LIMIT_FIELD_BYTES Size of one field value 65536
FUAST_LIMIT_INDEX_KEY_BYTES Encoded size of one indexed field. The default fits any value within the field limit. 131136
FUAST_LIMIT_TRANSACTION_MS Database time per handler call 5000
FUAST_LIMIT_STATE_ROWS, FUAST_LIMIT_STATE_BYTES Stored rows and row bytes per app 100000, 67108864
FUAST_LIMIT_JOBS_PENDING, FUAST_LIMIT_JOBS_PER_CALL, FUAST_LIMIT_JOB_ARGS_BYTES Pending jobs per app, jobs scheduled per handler call, job argument bytes (jobs) 10000, 1000, 65536
FUAST_LIMIT_DAILY_REQUESTS, FUAST_LIMIT_DAILY_MUTATIONS, FUAST_LIMIT_DAILY_EMAIL Daily quotas per app 100000, 20000, 100
FUAST_LIMIT_CPU_MS, FUAST_LIMIT_WALL_MS, FUAST_LIMIT_MEMORY_MB Isolate CPU time, wall-clock time, memory. fuast dev applies the wall-clock limit only. 5000, 10000, 128
FUAST_LIMIT_ACTION_MS Action runtime 5000
FUAST_LIMIT_ACTION_ARGS_BYTES, FUAST_LIMIT_ACTION_RESULT_BYTES Action argument and result size 16384, 49152
FUAST_LIMIT_WRITE_LOCK_WAIT_MS How long a write waits for the app's write lock 30000

fuast inspect and /__fuast/manifest show the limits in effect under limits, so you can check what a process picked up.

Older names still work but print a deprecation warning once: FUAST_DB_ROWS_RETURNED, FUAST_DB_ROWS_READ, FUAST_DB_BYTES_READ, FUAST_DB_DIRECT_GETS, FUAST_DB_SCAN_CALLS, FUAST_DB_WRITES, FUAST_DB_VALUE_BYTES (and FUAST_LIMIT_VALUE_BYTES), FUAST_DB_INDEX_KEY_BYTES, FUAST_DB_TRANSACTION_MS, FUAST_STATE_ROWS, FUAST_STATE_BYTES, FUAST_QUOTA_REQUESTS, FUAST_QUOTA_MUTATIONS, FUAST_QUOTA_EMAIL, FUAST_CPU_MS, FUAST_WALL_MS and FUAST_HANDLER_TIMEOUT_MS, FUAST_MEM_MB, FUAST_ACTION_TIMEOUT_MS, FUAST_WRITE_LOCK_WAIT_MS. When both an old and a new name are set, the FUAST_LIMIT_* name wins.

Unclaimed previews have their own family, read by the platform. Values must be positive whole numbers:

Variable Changes Default
FUAST_UNCLAIMED_DEPLOYS off refuses deploys without an account. on
FUAST_UNCLAIMED_TTL_HOURS Lifetime of a preview, from its first deploy 72
FUAST_UNCLAIMED_NEW_PER_IP, FUAST_UNCLAIMED_REDEPLOYS_PER_IP, FUAST_UNCLAIMED_ATTEMPTS_PER_IP New previews and redeploys per client address per UTC day (kept in the database, so a restart does not reset them), and deploy requests per 24 hours 5, 30, 100
FUAST_UNCLAIMED_MAX_LIVE Previews that may exist at once 500
FUAST_UNCLAIMED_MAX_IN_FLIGHT, FUAST_UNCLAIMED_BUILD_CONCURRENCY Anonymous deploys queued or building at once, and building at once. Keep the second below FUAST_BUILD_CONCURRENCY so signed-in deploys always have a build slot. 8, 1
FUAST_UNCLAIMED_DEPLOY_MAX_FILES, FUAST_UNCLAIMED_DEPLOY_MAX_BYTES Source files and bytes per anonymous deploy 200, 1048576
FUAST_UNCLAIMED_STATE_ROWS, FUAST_UNCLAIMED_STATE_BYTES, FUAST_UNCLAIMED_JOBS_PENDING Stored rows, row bytes, and pending jobs per preview 2000, 2097152, 100
FUAST_UNCLAIMED_STORAGE_BYTES Stored file bytes per preview 2097152
FUAST_UNCLAIMED_DAILY_REQUESTS, FUAST_UNCLAIMED_DAILY_MUTATIONS, FUAST_UNCLAIMED_DAILY_RERUNS Daily quotas per preview 2000, 500, 20000
FUAST_UNCLAIMED_DAILY_FETCH, FUAST_UNCLAIMED_FETCH_PER_RUN Outbound fetch calls per preview per UTC day (0 turns outbound fetch off for previews), and per handler call 100, 10
FUAST_UNCLAIMED_REPORTS_TO_SUSPEND Reports from different client addresses that suspend a preview 3
FUAST_UNCLAIMED_SWEEP_INTERVAL_MS, FUAST_UNCLAIMED_SWEEP_BATCH How often expired previews are deleted, and how many per run 60000, 20

Other operator settings are not limits on what a handler may do, so they keep their own names:

Variable Process Changes
FUAST_MAX_ISOLATES, FUAST_RUNTIME_MAX_APPS runtime Cached isolates and open app databases.
FUAST_ALLOW_PRIVATE_FETCH runtime 1 lets handlers fetch private addresses. Never set it on a shared platform.
FUAST_QUOTA_WORKSPACE_EMAIL, FUAST_QUOTA_INVITES platform Emails per workspace per day across its apps, and share invites per workspace per day.
FUAST_STORAGE_MAX_FILE_BYTES, FUAST_STORAGE_WORKSPACE_BYTES platform File size and storage per workspace.
FUAST_DEPLOY_MAX_FILES, FUAST_DEPLOY_MAX_BYTES, FUAST_DEPLOY_MAX_FILE_BYTES platform Deploy upload size.
FUAST_BUILD_TIMEOUT_MS, FUAST_BUILD_CONCURRENCY platform Sandboxed build time limit and parallel builds.
FUAST_DISABLE_RATE_LIMITS platform 1 turns off per-IP rate limits. For tests only.
FUAST_DEV_WRITE_LOCK_TIMEOUT_MS, FUAST_DEV_LOAD_TIMEOUT_MS fuast dev Local write-lock wait (defaults to FUAST_LIMIT_WRITE_LOCK_WAIT_MS) and the time a server bundle may take to load (10000).
FUAST_DEV_CLOCK_OFFSET_MS fuast dev Milliseconds added to the clock cron schedules are evaluated against (tests; default 0). Jobs use the real clock.

The endpoint body size, log sizes, email sizes, team table sizes, and the per-IP rate limits are fixed. A per-IP limit counts an IPv4 address, or a whole IPv6 /64, as one client. See reference for the rest of the platform environment.