Logs
Every environment keeps its app’s logs: what your code writes with console.log (and info, warn, error, debug), each request with its method, path, status and duration, uncaught exceptions with their stack, and cron and queue runs. Read them with the API, flatstack logs, or the get_logs MCP tool.
What is kept
| Plan | Logs are kept for |
|---|---|
| Hobby | 3 days |
| Pro | 7 days |
| Studio | 30 days |
| Unclaimed sandbox | 1 day |
Lines appear within about 10 seconds. Older lines are deleted once a day; a read never returns lines older than your plan keeps, whatever since asks for.
Secrets are removed before anything is stored, so they can’t be read back later:
- In objects you log, any field whose name contains
token,secret,password,key,authorizationorcookie, and fields namedbody,html,text,prompt,messagesorcontent, become[redacted]. - In text,
name=valueandname: valuepairs with names like those,BearerandBasiccredentials, passwords in URLs (postgres://user:…@host), and well-known key formats (Stripe, AWS, GitHub, Slack, OpenAI and Anthropic keys, Flatstack tokens, JWTs, private keys) become[redacted]. - Request query strings are never stored, only the path.
- A line longer than 8,192 characters is cut.
GET /v1/projects/{projectId}/logs
Needs logs:read. Owners, admins, developers and viewers have it; deploy tokens can carry it.
| Query | Meaning |
|---|---|
environment |
production (the default) or preview/<name>. A deploy token for one environment reads only that one. |
since |
ISO 8601 (2026-10-29T12:00:00Z) or relative: 30s, 15m, 2h, 7d. Default 1h. |
level |
The lowest level to return: debug, info, warn or error. warn returns warnings and errors. |
search |
Only lines whose message or path contains this text, ignoring case. |
limit |
Lines to return, 1 to 1000. Default 100. |
{
"environment": "production",
"since": "2026-10-29T11:00:00.000Z",
"until": "2026-10-29T12:00:00.000Z",
"retentionDays": 7,
"lines": [
{
"timestamp": "2026-10-29T11:58:02.114Z",
"level": "error",
"kind": "request",
"message": "POST /api/checkout 500",
"method": "POST",
"path": "/api/checkout",
"status": 500,
"durationMs": 41,
"deployId": "dep_…"
}
],
"hasMore": false,
"warnings": []
}
Lines are newest first. kind is log, request, exception, cron or queue. A request is warn at 4xx and error at 5xx or when your code threw. deployId is the deploy (or rollback) that served the line, or null for the placeholder Worker and for lines logged before 30 October 2026, when deploys started being recorded on each line.
hasMore: true means more lines match than were returned: narrow since or raise limit. warnings says when since reached past your plan’s retention, or when a search had too many logs to read in one go.
| Error | When |
|---|---|
400 validation_failed |
since, level or limit isn’t one of the forms above |
403 forbidden |
The token has no logs:read |
404 not_found |
No such project or environment in your account, or another environment than a deploy token’s |
flatstack logs
flatstack logs # the last hour of production
flatstack logs --since 15m --level warn
flatstack logs --env preview/checkout --search "stripe" --limit 500
flatstack logs --json # the API's response, for scripts and agents
Live tail (--tail) and filtering by function and end user are coming.
MCP
get_logs takes the same filters as the API: projectId, environment, since, level, search, limit. See Connecting AI tools over MCP.
As Markdown: api/logs.md