DaytonaDocs

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:

Python
# handler.py
import json
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
 
class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        raw = self.rfile.read(int(self.headers.get("Content-Length", 0)))
        payload = json.loads(raw or b"{}")
        result = {"greeting": f"hello {payload.get('name', 'world')}"}
        body = json.dumps(result).encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        self.wfile.write(body)
 
port = int(os.environ.get("RLP_FN_PORT", "8080"))
HTTPServer(("0.0.0.0", port), Handler).serve_forever()

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:

Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY handler.py .
CMD ["python", "handler.py"]

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.

Python
from rlp import Daytona
 
daytona = Daytona()
 
daytona.fn.deploy(
    "greet",
    image="ghcr.io/acme/greet:latest",
    vcpus=1,
    mem_mib=512,
    timeout_s=30,
    env={"LOG_LEVEL": "info"},
)
TypeScript
import { Daytona } from '@rlp/sdk'
 
const daytona = new Daytona()
 
await daytona.fn.deploy({
  name: 'greet',
  image: 'ghcr.io/acme/greet:latest',
  vcpus: 1,
  memMib: 512,
  timeoutS: 30,
  env: { LOG_LEVEL: 'info' },
})
cURL
curl -X POST https://api.rl.trydaytona.com/fns \
  -H "Authorization: Bearer $RLP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "greet",
    "image": { "type": "registry", "ref": "ghcr.io/acme/greet:latest" },
    "vcpus": 1,
    "mem_mib": 512,
    "timeout_s": 30,
    "env": { "LOG_LEVEL": "info" }
  }'

Once deployed, invoke it:

Python
print(daytona.fn.invoke("greet", {"name": "Ada"}))
# {"greeting": "hello Ada"}

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.

FieldDefaultMeaning
namerequiredPer-project unique name; DNS-label form [a-z0-9]([a-z0-9-]*[a-z0-9])?, 1–64 chars.
imagerequiredA registry reference, or a named project image.
handlerimage entrypointArgv to start the HTTP server. Empty uses the image entrypoint.
port8080Port the handler listens on (RLP_FN_PORT); 1–65535.
vcpus1Provisioned vCPUs; ≥ 1.
mem_mib512Provisioned memory (MiB); ≥ 128.
scratch_mib512Scratch disk (MiB); ≥ 64.
timeout_s300Max seconds for one invocation; 1–172800 (48h).
scaledown_window_s60Idle seconds before an instance scales to zero; ≥ 2.
max_concurrency1Invocations one instance serves at once; ≥ 1.
max_instancesunboundedOptional cap on concurrent instances — a spend guard, not a capacity setting.
env{}Environment variables for the handler.
snapshot_kindpre_entrypointCold-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:

cURL
curl -X PATCH https://api.rl.trydaytona.com/fns/greet/config \
  -H "Authorization: Bearer $RLP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "max_concurrency": 8, "scaledown_window_s": 120 }'

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.

On this page