Module reference

Everything a function declares, it declares in its own file, read at deploy time. One surface export — http, mcp, or app (never more than one) — plus config for runtime capabilities.

export const http

Deploys the default export as an HTTP endpoint at /f/<name>. The whole export is optional — a bare default handler deploys with the defaults below.

fieldtypemeaning
namestringFunction name, 1–64 of a-z 0-9 - _; becomes part of the URL. Default: the filename, or --name at push.
methodsstring[]HTTP methods it answers, e.g. ["GET","POST"]. Anything else gets 405. Default: ["POST"].
pathstringRoute pattern nested under the function, e.g. "/users/{id}"; captures arrive in request.params. Default: none — the function serves exactly /f/<name>.
access"public" | "private"Who may call the URL. "private": every call needs one of your API keys, on any server. "public": keyless even under --require-auth — what webhook targets and OAuth callbacks need. Undeclared: follows the server (open on rusted.sh). See security.
publicbooleanLegacy alias for access: "public". Contradicting an explicit access is a deploy-time error.
export const http = { name: "hook", methods: ["POST"], path: "/repos/{repo}", access: "public" };

export default async function handler(request, context) {
  const payload = await request.json().catch(() => ({}));
  return context.json({ repo: request.params.repo, ok: true });
}

Script mode

A file with no export or import statement is a script: its statements run top to bottom as the body of a GET handler, and its return is the response. Quick calculations and one-off scripts need nothing else.

const t = 1;
const b = 2;

return t + b;

request, context, fetch, console.log and top-level await are all in scope. The return value picks the content type: an object or array is JSON, a string is text unless it starts with a tag (then HTML), a number or boolean is text, no return is a null body, and context.json/text/html/redirect work as in a handler. A script declares nothing, so it has no capabilities — no context.db, secrets, state or objects — and takes its name and access from the push: rusted push calc.js --name calc --access public, or inline with no file at all: rusted push --script 'return 1 + 2' --name calc. --method and --path still override. Script mode is JavaScript: TypeScript goes through the bundler, which rejects a top-level return.

export const mcp

Deploys the module as an MCP server at /f/<name> — tools are the interface, so an mcp module must not have a default export. Arguments are validated against each tool's schema before its handler runs. See MCP.

fieldtypemeaning
namestringSame rules and default as http.name.
toolsobjectTool name → { description, inputSchema, handler }. inputSchema is JSON Schema; handler(args) is an async function whose return value becomes the tool result.
publicbooleanServe without any key. Default: connecting requires one of your API keys (Authorization: Bearer) — MCP is private by default, the opposite of http. Mutually exclusive with auth.
authobjectHost-validated OAuth instead of a rusted key: { type: "oauth", issuer, audience, scopes?, introspectionClientIdSecret?, introspectionClientSecretSecret? }. issuer is an https origin, audience an absolute https URL; the introspection pair are vault secret names, both or neither.
export const mcp = {
  name: "calculator",
  tools: {
    add: {
      description: "Add two numbers",
      inputSchema: { type: "object", properties: { a: { type: "number" }, b: { type: "number" } }, required: ["a", "b"] },
      async handler({ a, b }) { return a + b; },
    },
  },
};

export const app

The third surface: Express-style routes, middleware, and path parameters under one function's URL, built with the rusted.app() chain. Routes are the interface — an app module has no default export, and the route table is inspected and validated at deploy time like mcp tools. See Web apps.

export const app = rusted
  .app({ name: "todo-app", access: "public" })
  .use(loggingMiddleware)
  .get("/", homeHandler)
  .post("/todos/{id}/toggle", toggleHandler);

export const config

Runtime capabilities. Nothing is on by default — a function gets exactly what it declares, and the console shows what each function asked for.

fieldtypemeaning
secretsstring[]Names from your secret vault, decrypted into context.env.<NAME> per invocation — from the environment the call selects (/f/@stage/<name>). A declared secret missing from the vault refuses the invocation up front.
dbtrueThe account's SQL database at context.db — shared across all your functions, scoped per environment. Must be exactly true when present.
statetrueDurable JSON state at context.state (get/set/compare-and-swap), scoped per function and per environment. Survives redeploys and even deletion — rusted state purge is the one way it goes away. Must be exactly true when present.
objectsobjectS3-compatible bindings at context.objects.<BINDING>, binding name → { endpoint, bucket, region?, maxObjectBytes, accessKeyIdSecret, secretAccessKeySecret }. endpoint is a bare https origin (allowlisted by the operator), region defaults to "auto", and the two …Secret fields are vault secret names — credentials are resolved host-side and never reach JavaScript.
export const config = {
  secrets: ["GITHUB_TOKEN"],
  state: true,
  objects: {
    UPLOADS: {
      endpoint: "https://<account>.r2.cloudflarestorage.com",
      bucket: "uploads",
      maxObjectBytes: 5_000_000,
      accessKeyIdSecret: "R2_KEY_ID",
      secretAccessKeySecret: "R2_KEY_SECRET",
    },
  },
};

Every field is checked at deploy time — unknown fields, a module exporting both surfaces, state: false, or an access value outside the enum are refused with the reason, not deployed and left to fail later. rusted verify file.js runs the same checks without deploying, and rusted types writes rusted.d.ts so your editor knows all of this too.