Deploying Functions
Package a handler into an image, deploy it, and roll versions forward.
Deploying a function registers a handler under a project-scoped name and provisions the runtime shape it will run at. A deploy takes an image (a registry reference or a project image) plus a wire contract and scaling configuration, and produces an immutable version. Every field beyond name and image has a sensible default, so the smallest possible deploy names a function and points it at an image. This page walks an end-to-end example — a tiny handler, its image, the deploy, and a first invocation — then covers versioning.
The handler
A handler is any HTTP server that reads its port from RLP_FN_PORT and answers POST /. Daytona forwards each invocation's body to POST / and returns whatever the handler responds. Here is a complete, correct handler that parses a JSON body and returns a JSON result:
The image
Package the handler into an OCI image. The image's entrypoint should start the server; if it does, you don't need a custom handler argv at deploy time. A minimal Dockerfile for the handler above:
Build and push this image to a registry your project can pull, then deploy by its registry reference. If you'd rather not manage a build, deploy any prebuilt image that serves POST / on its port — the SDKs deploy registry references directly.
Note: The SDKs send registry references. Building from a Dockerfile at deploy time is also available through the REST API's multipart form — see the Functions API reference.
Deploying
Deploy with the SDK or the REST API. deploy is an upsert by name: the first call creates the function, and later calls create new versions.
Once deployed, invoke it:
Deploy configuration
Every field below except name and image is optional and defaults as shown. Functions are always non-spot, non-persistent, and burstable, homed in the caller's default region — there is no region, spot, persistent, secrets, or mode option.
| Field | Default | Meaning |
|---|---|---|
name | required | Per-project unique name; DNS-label form [a-z0-9]([a-z0-9-]*[a-z0-9])?, 1–64 chars. |
image | required | A registry reference, or a named project image. |
handler | image entrypoint | Argv to start the HTTP server. Empty uses the image entrypoint. |
port | 8080 | Port the handler listens on (RLP_FN_PORT); 1–65535. |
vcpus | 1 | Provisioned vCPUs; ≥ 1. |
mem_mib | 512 | Provisioned memory (MiB); ≥ 128. |
scratch_mib | 512 | Scratch disk (MiB); ≥ 64. |
timeout_s | 300 | Max seconds for one invocation; 1–172800 (48h). |
scaledown_window_s | 60 | Idle seconds before an instance scales to zero; ≥ 2. |
max_concurrency | 1 | Invocations one instance serves at once; ≥ 1. |
max_instances | unbounded | Optional cap on concurrent instances — a spend guard, not a capacity setting. |
env | {} | Environment variables for the handler. |
snapshot_kind | pre_entrypoint | Cold-start template; see Scaling. |
Versioning
Each deploy creates a new immutable version and points "current" at it. Redeploying the same name is how you roll a change forward — the new version becomes current and subsequent invocations use it. Version history is available via GET /fns/:name/versions.
Changing the image or the handler argv always requires a redeploy, because those are baked into the version. The runtime scaling knobs, however, can be updated on the current version in place — without a rebuild — through PATCH /fns/:name/config. That endpoint accepts max_concurrency, max_instances, timeout_s, and scaledown_window_s, and the change takes effect on the next invocation:
To remove a previously set instance cap, send an explicit "max_instances": null. See the Functions API reference for the full request and response shapes.