# Functions

A function is a unit of deployed backend logic (JavaScript/TypeScript, Python, or Ruby) that Volcano builds, packages, and runs on a managed runtime.

## What it is

A function is a unit of deployed backend logic (JavaScript/TypeScript, Python,
or Ruby) that Volcano builds, packages, and runs on a managed **runtime**. It
is invoked over HTTP, by name/alias, or on a schedule.

## How it relates

- Belongs to a **project**.
- Reads configuration and secrets from **variables**. By default it receives
  every project variable; declare a narrower
  [variable scope](https://docs.staging.volcano.dev/cli/project-configuration.md) to give it only the ones it needs.
- Connects to **databases** and **storage** in the same project.
- Its **visibility** (`private`, `authenticated`, or `public`) and
  **schedulers** can be declared in the
  [declarative config](https://docs.staging.volcano.dev/cli/project-configuration.md) or managed with the CLI.
- A **frontend route** can serve a public function under a path of a
  [frontend](https://docs.staging.volcano.dev/cli/frontends.md).
- Can be given an **alias** so you can invoke it by a friendly name.
- Work that has to run for hours belongs in a
  [durable function](https://docs.staging.volcano.dev/cli/durable-functions.md) instead, which is a separate
  collection with its own commands.

The CLI discovers functions in the `volcano/functions` directory, detects the
runtime from source file extensions, and uploads a packaged archive.

If a `volcano-config.yaml` is present, `functions deploy` also sends the
`variable_scope` and `variables` declared there for each function it uploads.
Functions the manifest does not mention keep their existing scope. The manifest
is only read — deploying never writes it back. See
[variable scope](https://docs.staging.volcano.dev/cli/project-configuration.md).

Because those declarations come from the manifest, a manifest that is present
but cannot be read stops the deploy before anything is uploaded, and the error
says what to fix. That includes a `${VAR}` reference anywhere in the file whose
environment variable is not set in the deploying shell, even in a section
unrelated to functions. Deploying past it would upload a function without the
scope it declared, giving it every project variable. With no
`volcano-config.yaml` at all there is nothing to declare and deploy runs
normally.

## Function layout

Each supported file or directory directly under `volcano/functions` is one function.
Names starting with `_`, such as `_lib/`, hold shared code that every function
archive includes.

| Entry | Function | Entry file |
|---|---|---|
| `hello.js`, `hello.mjs`, `hello.py`, `hello.rb` | `hello` | the file itself |
| `hello.ts`, `hello.mts`, `hello.cts`, `hello.tsx` | `hello` | the file itself, compiled by Volcano |
| `checkout/` | `checkout` | `index.js`, else `main.py` or `main.rb`, else `index.cts`, `index.mts`, `index.ts` or `index.tsx` |

### TypeScript

The CLI uploads a TypeScript handler as source, and Volcano compiles it to
JavaScript during the build, in the cloud and in local mode:

- Types are removed without being checked, so a type error doesn't fail the
  deploy. Run `tsc --noEmit` in your own CI to catch type errors.
- `.mts` compiles to an ES module and `.cts` to CommonJS. `.ts` and `.tsx` are
  ES modules when the function's `package.json` sets `"type": "module"`,
  CommonJS otherwise.
- `.tsx` compiles JSX with React's automatic runtime, so you don't import
  React, but `react` (and a renderer such as `react-dom`) must be in the
  function's `package.json` dependencies. A directory function's
  `tsconfig.json` can choose other JSX settings, such as `"jsx": "react"` with
  `"jsxFactory": "h"`, or `"jsxImportSource": "preact"`. A single-file
  function uploads without a `tsconfig.json`, so put the handler in a
  directory to change them.
- Imports through `paths` in a `tsconfig.json` inside the function's directory
  resolve. Packages from `package.json` load from the installed dependencies.
- `.ts`, `.mts` and `.cts` never change what an existing function deploys:
  `hello.js` or `hello.py` beside `hello.ts` or `hello/index.ts`, or
  `checkout/index.js`, `index.mjs`, `index.cjs`, `main.py` or `main.rb` beside
  `checkout/index.ts`, deploys that file instead. A `hello/` directory beside
  `hello.ts` deploys the directory.
- `.tsx` ranks after the other TypeScript: `hello.ts` beside `hello.tsx`, or
  `index.ts` beside `index.tsx` in a directory, deploys the `.ts` file. A
  `hello.ts` file also deploys instead of a `hello/` directory with only an
  `index.tsx`.
- One layout deploys differently than with CLI 0.77.0 and earlier: a `hello/`
  directory with `index.mjs` or `index.cjs` beside `index.tsx` now deploys
  that JavaScript instead of a `hello.ts` file, as Git deploy does. Earlier
  CLIs didn't find that directory.
- Two TypeScript files with one name and no JavaScript, such as `hello.ts` and
  `hello.mts`, stop the deploy until you keep one. Two TypeScript indexes in
  one directory, such as `checkout/index.ts` and `checkout/index.mts`, fail
  that function's build.
- Declaration files such as `types.d.ts` aren't functions. A directory needs
  its handler at its top, such as `checkout/index.ts`, not
  `checkout/src/index.ts`.

See [TypeScript](https://docs.staging.volcano.dev/platform/functions/creating-functions.md#typescript) for how the
build compiles it.

## CLI operations

| Operation | Command |
|---|---|
| Deploy one or all | `volcano functions deploy [-a \| -f <name\|path>]` |
| List | `volcano functions list` |
| Get | `volcano functions get <name>` |
| Set visibility | `volcano functions update <name> --visibility private\|authenticated\|public` |
| Delete | `volcano functions delete <name>` |
| Invoke | `volcano functions invoke <name> [--payload …] [--json]` |
| Logs | `volcano functions logs <name>` |
| Search logs across functions | `volcano logs` (see [logs.md](https://docs.staging.volcano.dev/cli/logs.md)) |
| Supported runtimes | `volcano functions runtimes` |
| Deployable regions | `volcano functions regions [--json]` |
| Aliases | `volcano functions alias set\|list\|delete …` |
| Schedulers | `volcano functions schedulers create\|list\|enable\|disable\|delete …` |

Prefix with `cloud` (e.g. `volcano cloud functions deploy`) to target cloud.
Without the prefix, function commands always target local development.

Cloud deploys use latest-wins queueing. If the function is already deploying,
the new source replaces any older queued deploy and runs next. Delete supersedes
queued deploys; later deploys are rejected until deletion finishes.

## Visibility

Visibility decides who can invoke a function:

| Visibility | Who can invoke it |
|---|---|
| `private` | Service keys and schedulers |
| `authenticated` | Also your project's signed-in users, including [anonymous sign-ins](https://docs.staging.volcano.dev/platform/authentication/anonymous-users.md) |
| `public` | Also anon keys with `functions.invoke`, and [frontend routes](https://docs.staging.volcano.dev/cli/frontends.md#function-routes) |

A refused caller gets:

| Function | Caller | Answer |
|---|---|---|
| `private` | Anyone but a service key or scheduler | `404`, the same as for a function that does not exist |
| `authenticated` | Anon key, invoking by ID | `403` |
| `authenticated` | Anon key, invoking by name, as the SDK does | `404` |

If your app gets 404 for a function you deployed, check its visibility with
`volcano cloud functions get <name>`.

New functions start `private`. `functions deploy` says so for each function it
creates and prints the command that lets signed-in users in:

```text
  Deployed notes-summary (new, visibility private)

New functions are private: only service keys and schedulers can invoke them.
To let your project's signed-in users call one, run:
  volcano functions update notes-summary --visibility authenticated
Or declare its visibility in volcano-config.yaml and run volcano config deploy
```

A deploy does not apply the `visibility` in
[`volcano-config.yaml`](https://docs.staging.volcano.dev/cli/project-configuration.md#function-visibility). When the
manifest already declares a level for a new function, the hint points at
`volcano config deploy` instead.

`--public` is the same as `--visibility public`. `--private` is no longer
accepted: it used to let signed-in users in, which is `authenticated` now, so
pick the level you mean. A function that a frontend route forwards to has to
stay `public`; `functions update` lists the routes to delete first.

`functions update` sets the level of standard functions. For a
[durable function](https://docs.staging.volcano.dev/cli/durable-functions.md#visibility), declare `visibility` in
`volcano-config.yaml` and run `volcano cloud config deploy`.

`functions get` shows the level, and under "Routed from" every frontend path
that forwards to the function:

```text
Visibility: public
Routed from: web /api/session
```

## Examples

[`volcano deploy`](https://docs.staging.volcano.dev/cli/deploy.md) deploys the functions together with the
project's variables, durable functions, frontends, and configuration. Use
`functions deploy` to deploy only functions.

```bash
# Deploy everything, or a single function by name or path
volcano functions deploy --all
volcano functions deploy -f get-notes
volcano functions deploy -f volcano/functions/get-notes.js

# Invoke with a JSON payload; --json prints compact machine output
volcano functions invoke hello --payload '{"name":"Ada"}'
volcano functions invoke hello --json
volcano functions invoke --id 33333333-3333-4333-8333-333333333333

# Let signed-in users invoke a function
volcano functions update notes-summary --visibility authenticated

# Tail build/runtime logs
volcano functions logs hello

# Schedule a function (cron), then disable it
volcano functions schedulers create hello --name refresh-cache --cron "*/5 * * * *"
volcano functions schedulers disable hello --name refresh-cache

# Invoke-by-alias
volcano functions alias set hello 44444444-4444-4444-8444-444444444444
volcano functions invoke hello
```

`schedulers list` shows each scheduler's health, how many runs in a row have
failed, and the last error of a failing one. A run fails when Volcano cannot
invoke the function; an error the function itself returns does not count. To be
alerted when a scheduler keeps failing, see [notifications.md](https://docs.staging.volcano.dev/cli/notifications.md).
