Deploying and running functions
Deploy from the console, the CLI or GitHub; dependencies; versions and rollback; environments; calling synchronously, asynchronously or streaming; response headers, errors and retries; and reading your data safely from a function.
Ways to deploy
| From | How | Good for |
|---|---|---|
| Console | Functions › your function › edit › Save & deploy | Small functions, quick fixes |
| CLI | sov fn deploy ./folder --name hello --note "…" | Code in your repository, CI |
| GitHub | Import a function from a connected repository; commit console edits back | Teams that review code in GitHub |
The entry file is main.py (Python) or index.mjs / index.js (Node.js); --entrypoint and --handler change it. Every deploy is a new version; a deploy that fails never replaces the version serving traffic.
sov fn deploy ./functions/send-receipt --name send-receipt --note "retry on 5xx"
sov fn versions send-receipt
sov fn rollback send-receipt # back to the previous versionDependencies
The standard library (Python) and built-ins such as fetch (Node.js) are always there. To ship packages, vendor them with your code and deploy with --include-deps (bundles node_modules or vendored Python packages) — available on paid plans.
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Bundle your own function dependencies | — | ✓ | ✓ | ✓ | ✓ |
Environments
Deploying through an environment's URL (staging, a version) creates that environment's own copy; production keeps serving its version. When the change is ready, promote it to production — Environments, staging and deploying to production. Secrets and environment variables stay per environment, so staging never uses production keys.
Call it
| Way | Use for |
|---|---|
POST /functions/v1/<name> (sovaria.functions.call) | Answers within a request: the response is what the function returns. |
Asynchronously (sovaria.functions.invokeAsync, sov fn invoke --async) | Long work. You get an invocation id at once; read its status and result later (sovaria.functions.invocationStatus(id), GET /api/v1/fn/invocations/<id>). |
| Streaming | Send output as it is produced (AI responses) — Local development, logs and streaming. |
| Triggers and schedules | Run on database, auth, storage or realtime events, or on a cron schedule — Event triggers. |
Successful responses carry X-Sovaria-Invocation-Id (find the run in the logs), X-Sovaria-Duration-Ms and X-Sovaria-Compute-GB-Seconds.
Errors
| You get | Because |
|---|---|
401 | The function requires sign-in and the caller isn't signed in. |
403 | Only the service key may call it, or the browser origin isn't allowed. |
404 | No function with that name in this environment. |
409 | It was saved but never deployed. |
413 | The request body is over the function's limit. |
429 | The function's rate limit, or the organization's concurrent-run limit, was reached — retry after Retry-After. |
5xx | Your code raised an error or ran out of time or memory. The run is logged as FAILED or TIMEOUT with the error. |
HTTP calls are not retried for you. Event triggers retry failed runs and keep the ones that keep failing in a dead-letter queue, so write handlers that can safely run twice (check whether the work was already done before doing it).
Start-up and concurrency
- Functions run in isolated sandboxes that are reused between calls when possible; the first call after a deploy or a quiet period can take longer.
- Create clients and read configuration at module level, not inside the handler, so warm calls skip it.
- How many runs may execute at once is set by your plan; beyond it a call waits briefly, then gets
429 PLAN_LIMIT_REACHED(fn.concurrency) withRetry-After: 2.
| Free | Pro | Ultra | Team | Enterprise | |
|---|---|---|---|---|---|
| Concurrent function invocations | 5 | 50 | 200 | 500 | 2,000 |
| Monthly function invocations | 250,000 | 2,000,000 | 6,000,000 | 30,000,000 | 100,000,000 |
| Monthly function compute (GB-seconds) | 10,000 | 100,000 | 300,000 | 1,500,000 | 5,000,000 |
Read and write your data from a function
Store a server key as a secret and call your project's API with it. Because a server key passes every access policy, decide in your code what the caller may do — use context.caller — before acting for them.
const URL = process.env.SOVARIA_URL // https://<project-ref>.sovarias.in
const KEY = process.env.SOVARIA_SERVICE_ROLE_KEY // bound as a secret
export async function handler(event, context) {
const userId = context.caller.user_id
if (!userId) return { error: 'sign in first' }
const res = await fetch(`${URL}/api/v1/sql/query`, {
method: 'POST',
headers: { apikey: KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ sql: 'select id, total from orders where customer_id = $1', params: [userId] }),
})
return await res.json()
}- Add your project host to the function's allowed hosts — functions can only reach hosts you list.
- Pass values as
params, never inside the SQL string. - Prefer a custom key with only the access the function needs over the service role key (Keys, tokens and credentials).