Create your first endpoint
Standalone functions use a manifest and packaged handlers in arvumi/functions/, relative to your application root. You can write handlers in Node.js or Python.
For a dependency-free Node.js function, add these two files to your repository.
{
"version": 1,
"runtime": "node",
"routes": [
{
"path": "/api/hello",
"entrypoint": "hello.cjs",
"env": []
}
]
}
exports.handler = async (request) => {
const query = new URLSearchParams(request.query ?? "");
return {
status: 200,
headers: { "content-type": "application/json" },
body: { message: `Hello, ${query.get("name") ?? "world"}!` }
};
};
Commit and push the files. Create a project for the repository, leave install, build, and output settings unset for this example, and deploy the production branch. Once ready, replace your-project below with your project’s name:
curl 'https://your-project.arvumi.com/api/hello?name=Arvumi'
# {"message":"Hello, Arvumi!"}
Requests, responses, and routes
Routes match exact paths under /api/. Dynamic path parameters and extension inference are not supported by this manifest. Routes accept all HTTP methods; check request.method in your handler to restrict them. Entrypoints are relative to arvumi/functions/.
| Request field | Value |
|---|---|
method, path | HTTP method and pathname. |
query | Raw query string without ?, or null. |
headers | Header values by name. Use header_pairs for repeated values. |
body | UTF-8 text, base64 for other bytes, or null. Check isBase64Encoded. |
Return { status, headers, body }. Non-string ordinary bodies are JSON encoded; set the content type explicitly. Request bodies are limited to 1 MiB and decoded responses to 4 MiB.
Use Python
For a separate Python project, set "runtime": "python" and "entrypoint": "hello.py" in the same manifest structure. Create this handler:
def handler(request):
return {
"status": 200,
"headers": {"content-type": "application/json"},
"body": {"message": "Hello from Python!"},
}
A manifest uses one language. Python also supports async def handler(request).
Package your dependencies
Compile TypeScript before deployment. Include Node.js production dependencies inside arvumi/functions/node_modules/; repository-root modules are not implicitly copied. Python dependencies must also be packaged in the function artifact. Use the managed build environment for native dependencies so they match the runtime.
A function-only deployment does not publish your repository root as a static website. To include static assets, choose a separate output directory such as dist. Do not combine a standalone manifest with a Next.js server; Next.js uses Arvumi’s injected adapter.
Configuration and secrets
Each route’s env array explicitly allows the project variables it can read. An empty or omitted array passes none. Add exact, case-sensitive keys such as "env": ["DATABASE_URL"] to use a managed database, then redeploy. Read the value through process.env.DATABASE_URL in Node.js or os.environ["DATABASE_URL"] in Python.
Set project resource defaults in Settings → Deploy Config → Function defaults. Timeouts, concurrency, CPU, and memory are subject to your plan. Changes apply to new deployments. Routes can override individual defaults with a settings object.
Autoscaling
Arvumi adjusts the number of function workers to handle incoming requests. Each standalone route scales independently, up to its configured maximum concurrency. Each worker handles one request at a time; increasing concurrency allows more workers to run in parallel.
After a period without traffic, functions scale down to zero workers. A new request starts them again. This startup can add latency, so account for it when designing time-sensitive endpoints.
Set maximum concurrency and per-worker resources in Settings → Deploy Config → Function defaults, then redeploy to apply them. Limits are subject to your plan. Global capacity is finite. These settings cap scaling but do not reserve hardware; requests can queue while workers start or when capacity is unavailable.
Function compute costs
Function CPU and memory are charged for forwarded request duration using the configured resources. This duration includes activation, queueing, and response streaming, so it can be longer than handler execution alone. Warm idle time between requests is free, including while a worker waits to scale to zero.
Builds use allocated CPU and memory. Deployment storage, delivered response data, plan fees, and paid database packages are separate. See pricing and your team’s Billing page for rates and credits.
Choose per-worker resources and maximum concurrency to suit your workload. Smaller allocations can reduce resource use, but insufficient resources can slow requests or cause failures. Concurrency limits control parallel workers; they are not a total spending cap.
Design for the runtime
- Workers can be reused, but module globals and temporary files are not durable storage. Keep persistent data in a database.
- Implement your application’s authentication and validate request inputs. A deployed endpoint is publicly reachable unless protected.
- Use
console.logorprintfor runtime logs; avoid logging secrets.