deploy.json
The plan the command inferred, and the one file your AI edits when a guess is wrong.
The first deploy writes deploy.json into the app's folder. It records everything the platform decided, with the evidence, and it is what your AI edits instead of passing flags. It contains no secrets and is safe to commit.
{
"version": 1,
"project": { "id": "prj_...", "slug": "family-books" },
"packageManager": "pnpm",
"framework": "nextjs",
"runtime": { "tier": "a", "base": "node22", "arch": "arm64", "memoryMb": 512, "timeoutSec": 30 },
"build": { "planner": "railpack" },
"database": { "engine": "postgres", "orm": "drizzle", "migrate": "npm run db:migrate" },
"storage": { "enabled": true },
"jobs": [{ "name": "monthly-report", "schedule": "0 2 1 * *", "path": "/api/reports/monthly" }],
"secrets": { "required": ["RESEND_API_KEY"], "provided": ["DATABASE_URL", "PORT"] },
"egress": { "allow": ["api.resend.com"] },
"speed": { "enabled": true, "images": true },
"auth": { "library": "none" },
"signals": [{ "for": "framework", "evidence": "next.config.ts present", "file": "next.config.ts" }]
}
What survives a re-deploy
Detection runs again on every deploy, and facts about the code win. But some things only a person or the platform could know, and those are kept from the existing file:
project: assigned by the platform.runtime.memoryMb,runtime.timeoutSec,runtime.start: hand-tuned resources.build.command,build.outputDir: explicit overrides.egress.allowandjobs: unions. Additions are deliberate and kept.database.migrate: if the engine is unchanged.speed.enabledandspeed.images: only a person turns these off, so re-detection never turns them back on.services[].project.id: the ids the platform gave each part, matched by folder.
Fields worth knowing
runtime.tier:afor ordinary request/response apps;bwhen the app needs a process that outlives a request (SQLite, WebSockets, in-process cron). Detected, not chosen.egress.allow: the outside hosts the app may call. By default an app has no internet access at all, which is what stops a compromised app from leaking data. Detection proposes the hosts it sees in the code; your AI adds more here when needed.speed.enabled: on by default. Every page gets a small script (/_ocl/speed.js, readable in the page source) that starts loading the next page when a link is hovered, touched or scrolled into view, so the click is instant; and static files with no cache header get sensible ones. It only ever fetches same-site links with GET, never anything that looks like an action, and it sends nothing anywhere. Set it tofalseif the app needs to be served exactly as written — a strict content-security policy, or a page that must not be prefetched. Mark one link withdata-no-prefetchto exclude just that link.speed.images: on by default. Every<img>pointing at a JPEG, PNG or WebP on the site gets asrcsetof resized copies (384 to 1920 pixels wide, served as WebP where the browser accepts it), so a phone downloads a phone-sized picture instead of the 4 MB original. The original file is untouched and stays the fallback. Images that already have asrcset, SVGs, GIFs, and anything markeddata-no-optimiseare left alone. Set tofalsefor a site that must serve its originals exactly.auth.library: if the app implements its own login, this names it and the deploy warns that the platform can replace it.services: present only at the top of a repository that holds several apps. Lists each part's name and folder, and after the first deploy its id. See Several apps in one project.signals: why each decision was made. Read these before overriding anything.