This document defines the per-function manifest used by the runtime.
- Schema file:
schemas/function-manifest.v2.schema.json - Base schemas:
schemas/base/common.schema.jsonschemas/base/network.schema.json
- JSON Schema draft:
2020-12
The runtime accepts only:
manifestVersion: 2
Any payload using manifestVersion: 1 is rejected.
The manifest lets each function declare:
- Deploy flavor (
flavor):singlerouted-app
- Optional route table (
routes) for routed apps:kind: "function"routes with per-routeentrypointkind: "asset"routes withassetDir
- Environment variables (
env.allow,env.secretRefs) - Network allowlist (
network.allow) - Optional resource limits (
resources) - Optional auth and observability preferences
- Optional profile overrides (
profiles)
The runtime enforces internal SSRF deny rules regardless of the manifest.
- A manifest cannot allow entries that collide with deny ranges from
runtime-core/src/ssrf.rs. - If
network.allowcontains denylisted targets, deployment fails. *is not allowed innetwork.allow.
At runtime, when a manifest is attached to a function:
network.allowis enforced as a per-function allowlist.env.allowandenv.secretRefsare enforced as per-function env controls.- Resource fields from
resourcesare applied intoIsolateConfiglimits.
When no manifest is attached, runtime behavior remains the default policy.
flavor: "single"- must not define
routes.
- must not define
flavor: "routed-app"- must define at least one route.
kind: "function"route:- requires non-empty
entrypoint - cannot define
assetDir
- requires non-empty
kind: "asset"route:- requires non-empty
assetDir - cannot define
entrypoint - if
methodsis provided, onlyGETandHEADare allowed
- requires non-empty
Deploy endpoint:
POST /_internal/functions- Required header:
x-function-name - Optional header:
x-function-manifest-b64 - Optional header:
x-function-manifest-profile
x-function-manifest-b64 must contain the manifest JSON encoded as Base64.
If present, the server validates:
- JSON decode / parse
- JSON Schema v2020-12 (v2 schema)
- Semantic checks (flavor/routes and denylist)
If validation fails, response is 400 Bad Request.
If the header is absent but the uploaded BundlePackage contains an embedded manifest (generated by thunder bundle --manifest ...), the deploy flow resolves and applies that embedded manifest.
PUT /_internal/functions/{name}:- If
x-function-manifest-b64is provided, the function manifest is replaced. - If
x-function-manifest-b64is omitted, the existing manifest is preserved.
- If
POST /_internal/functions/{name}/reload:- Keeps the currently attached manifest.
GET /_internal/functions/{name}/manifest
Responses:
200: returns currentResolvedFunctionManifest404: function exists without manifest ({"error":"manifest not configured for function"})404: function not found ({"error":"not found"})
thunder watch deploys functions without attaching a manifest automatically.
If you need manifest-enforced behavior in development, deploy via admin endpoint with x-function-manifest-b64.
{
"$schema": "https://thunder.dev/schemas/function-manifest.v2.schema.json",
"manifestVersion": 2,
"name": "hello",
"entrypoint": "./index.ts",
"flavor": "single",
"env": {
"allow": ["LOG_LEVEL"],
"secretRefs": ["APP_SECRET"]
},
"network": {
"mode": "allowlist",
"allow": ["api.example.com:443"]
},
"resources": {
"maxHeapMiB": 128,
"cpuTimeMs": 50000,
"wallClockTimeoutMs": 60000
}
}