Skip to content

Functions reference

Rule Value
Directory functions/ at the root of the project. If the project sets a root directory, inside that
Entry points Every .js or .ts file directly inside functions/. One file is one function
Name The file name without its extension. Lowercase letters, digits and hyphens; starts and ends with a letter or digit; at most 128 characters
Subdirectories Shared code. Never deployed on their own, bundled into whatever imports them
Imports Relative imports and npm packages your build installed are bundled with esbuild into one file per function. Node built-ins stay external
Build step None. TypeScript types are stripped, not checked
When Production deploys only: a push to the production branch, or a promotion. Preview builds skip the directory
Bundle size 900 KB per function. Over that the build fails
Removal Deleting the file and deploying removes the function. Rolling back to an earlier deployment restores the functions that deployment had

A file whose name breaks the rule fails the build with [functions] Build failed: invalid function name, and so does a .js and a .ts file sharing one name. Nothing is deployed from a failed build, so the previous deployment, functions included, stays live.

export default async function handler(request: Request, context: Context): Promise<Response>

request is a Web API Request. The return value is a Response, or a promise of one. Both are Node 22 natives, as are Headers, ReadableStream, AbortSignal and fetch; there are no polyfills and no deploybase-specific types.

Four export shapes are accepted, resolved in this order. We recommend the first.

Shape Example
Default export function export default function handler(request, context) {}
Default export object with fetch export default { fetch(request, context) {} }
Named export fetch export function fetch(request, context) {}
CommonJS assignment module.exports = function (request, context) {}

request.url is the function’s own public URL, https://{name}-{subdomain}.fn.deploybase.eu/, plus whatever query string the caller sent, on both doors. Headers arrive lower-cased; host is the function’s hostname.

context has two members:

Member What it does
context.env An object of environment variables. Empty of anything you set until environment variables ship
context.waitUntil(promise) Lets work outlive the response on the HTTPS door: the reply is sent and the promise keeps running, with a rejection logged rather than thrown. On a queued call it does nothing, because the container exits when the handler returns. Work that must complete belongs before the return

Streaming response bodies work on the HTTPS door, including text/event-stream, and multiple Set-Cookie headers are preserved. On a queued call the body is read in full before it is stored, and Set-Cookie headers are joined into one.

Runtime: Node 22 on both doors.

Item Value
Pattern https://{name}-{subdomain}.fn.deploybase.eu
{subdomain} The project’s subdomain, the first label of {subdomain}.sites.deploybase.eu. Shown in project settings
TLS Automatic. Plain HTTP redirects to HTTPS
Length {name}-{subdomain} together must fit in 63 characters, the DNS label limit. A longer combination is refused at deploy time with a line in the build log
Unknown hostname 404
Custom domains Not available. A function answers at its own hostname only; there is no way to route a path on your site’s domain to it

Every request goes through the component that scales instances. It adds an x-keda-http-cold-start header to the reply, true when the call waited for an instance to start.

One row per limit. The closed-beta column is what every enrolled team gets today, whatever its plan.

Limit Closed beta After the beta
Memory per instance 512 MB Per plan, see pricing
Concurrent requests per instance 10, then a second instance starts Per plan
Instances per function Up to 3 Per plan
Request budget 60 seconds Per plan
Request body, HTTPS door 10 MiB, then 413 Same
Request body, queued door 1 MB Same
Warm instances 0. Every function scales to zero after about two minutes without traffic Per plan
Cold start 2 to 5 seconds, measured on small handlers. A start that also has to bring up a node takes longer Same
Requests per month Not enforced. Fair use; abusive traffic may be throttled Per plan
Outbound network HTTPS to the public internet. Port 80, private ranges and the cloud metadata address are blocked Same

The request budget is not configurable during the beta.

The 60-second budget bounds what the caller sees, not what your code does. When it expires:

  • If nothing has been sent yet, the caller gets a 504.
  • If the response had started, the connection is cut mid-body.

Either way the handler keeps running until it finishes or the instance is replaced, because JavaScript has no way to cancel a running promise from outside. Side effects after the deadline still happen: a database write, an email, a third-party call. Do not rely on a timeout to cancel work; bound it inside the handler with an AbortSignal or a deadline of your own.

On a queued call the same budget applies. The container is stopped when it expires, the invocation ends as timed_out, and the poll reply carries the timeout message listed under queued calls.

Status Cause
404 No function at this hostname: unknown name, unknown subdomain, team not in the beta, or not deployed yet
413 Request body over 10 MiB
500 The handler threw, returned a rejected promise, or returned something that is not a Response
504 The request budget expired before any byte was sent

No stack trace or error text reaches the caller in any of these. A 500 is logged with the error on our side; the dashboard does not show HTTPS-call logs yet, so to read the error reproduce the call through the queued door.

The queued door runs the same file in a fresh container per call. Both endpoints are public and need no authentication. The API reference holds the full schemas: invoke and poll.

Endpoint Status Reply
POST /api/v1/public/functions/{subdomain}/{name} 202 Body {"data": {"invocation_id", "status": "pending", "poll_url"}}
GET /api/v1/public/functions/{subdomain}/{name}/invocations/{id} 200 Body {"data": {"id", "status", "started_at", "finished_at", "response_status", "response_headers", "response_body", "error_message"}}

Base URL https://api.deploybase.eu. The poll_url is relative to it. The method, query string, headers and body of the POST are what the handler receives as its Request.

Rule Value
Statuses pending, running, then one of completed, failed, timed_out
Result fields response_status, response_headers and response_body (base64) appear once the status is terminal. A failed call whose handler threw still carries the handler’s own 500 response
error_message Present on failed and timed_out. One of the sentences below, never the error itself
Request body 1 MB. A larger body is cut at 1 MB today rather than refused; this will become a 413
Rate limit 20 requests per minute per IP address across both endpoints, then 429
In flight 10 queued calls per team at once, then 429 with Too many concurrent invocations
Memory 512 MB
Retention Request, result and console output are kept for 7 days, then deleted
Access Not gated by the beta. Any team’s functions can be queued

The error_message sentences, exactly as they appear:

Ended as error_message
timed_out The function did not finish within its timeout of 60s.
failed The function ran out of memory.
failed The function returned an error. Check the invocation logs.
failed The function did not return a valid response.
failed This function is not deployed. Redeploy the project and try again.
failed The function could not be run. This is a platform issue; please retry.

Two more appear only when a call is reclaimed after a platform restart: The function did not finish before its timeout. and The function was never started. This is a platform issue; please retry.

Everything a queued call wrote to console.log and console.error is shown on the function’s page in the dashboard under Invocations, for members of the team only; it is never part of the public poll reply. Logs for HTTPS calls are not visible yet.

Environment variables for functions are not available yet. context.env exists so that code written against it keeps working when they ship, but it holds nothing you set: the project environment variables reach builds only, and a function has no access to them at request time. Watch the changelog. Until then, a value a function needs has to be in the code, which means in the repository.

Data Where and for how long
Queued calls The request headers and body, the result and the console output are stored in Paris for 7 days
HTTPS calls Not recorded. No request or response is stored
Bundles Stored in a private storage zone in Germany, deleted with the deployment
Client addresses The queued endpoints are rate limited per IP address, so the address is kept for that bookkeeping and cleaned up on a schedule. Beyond the request headers themselves, nothing about the caller of a queued call is stored

Our DPA covers personal data your functions process. Functions are provided under the beta terms at app.deploybase.eu/functions-beta.