Skip to content
Docs · Build & deploy

Functions

One JavaScript module that answers HTTP requests at its own edge URL, https://hk-<project>--<function>.harakumo.app. For webhooks, small APIs, proxies and redirects.

View as Markdown
All topics
On this page

A function is one ES module with a default fetch handler, deployed to the edge. Each request runs at the location nearest the caller with no server to size or keep awake. Create one with code, or without code to get a starter handler you replace later.

worker.jsHTTPS responseone module, answering at its own URL on the Harakumo edge

The address

Every function is served at https://hk-<project-slug>--<function-name>.harakumo.app — never under the project's own site address. The create response carries it as function.url.

Functions created before the move to harakumo.app have moved there, and url is the address to use. Their old harakumo.com address no longer runs the function: it redirects to the new one (301 for GET and HEAD, 308 for anything else, so a POST is sent again as a POST with its body). Webhook senders and pages on other sites usually do not follow redirects, so give them the new address.

Runtimes

runtimeWhat the code gets
node22 (default), node20Web APIs plus the Node.js compatibility layer: node:crypto, Buffer, process.env.
edgeWeb APIs only: fetch, Request and Response, crypto.subtle, streams.

Environment variables

  • The project's production variables are available as env.NAME in the handler.
  • They are read when the function deploys. After changing one, redeploy the function with its code (PUT /api/functions/:id).
  • The function receives them as secrets: the handler reads env.NAME as usual, and the values cannot be read back from where the function runs. In Harakumo they stay visible to anyone who can read the project's environment (developers and above), so they are configuration, not a vault.

Status and failed deploys

  • status is creating while the first deploy runs, active once the function answers at url, and error when its last deploy (or a delete) did not go through. last_error says why; url is null unless the function is active.
  • Code the edge refuses (a syntax error, an import that does not exist, too much work while the module loads) is answered with 400 and the edge's own reason. On create nothing is kept; on redeploy the running version keeps serving.
  • Problems on our side answer 502 or 503 with what went wrong; a 503 carries Retry-After. A failed deploy is never reported as a working function.
  • If the code uploaded but its address could not be connected, the function is kept with status error: redeploy it (PUT /api/functions/:id) to try again, or delete it.

Versions and rollback

Every deploy that changes a function's code is a version, numbered from 1: the create, a redeploy with new code, and a rollback. Deploying the same code again is not a new version. The newest 20 are kept, and the running one too if it is older; current is the version the function runs now. Its page in the dashboard lists them.

A version whose status is failed was refused when it was deployed: it never ran, and the version before it kept serving. last_error says why.

A rollback deploys a kept version's code again, with the runtime it ran with, as a new version whose rolled_back_from names the one it came from. It runs with the project's production variables as they are at that moment: a version records the names of the variables it was deployed with (env_keys), never their values.

A rollback fails the way a redeploy does. When the code is refused, the version that was live keeps serving, and the answer says why and which version that is. It takes the same permission as a redeploy; anyone in the workspace can list versions, and a version's code is for developers and above, like the function's own code.

List versions
const { versions, current } = await hk.functions.versions(fn.id);
// versions, newest first: [{ version: 3, status: 'deployed', current: true, rolled_back_from: 1, env_keys: ['API_KEY'], … }, …]
Roll back
const { version, url } = await hk.functions.rollback(fn.id, 2);
// version 2's code is live again, as a new version

Limits

  • One module, at most 200 KB, no npm install and no bundler — bundle dependencies yourself if you need them.
  • Code that does not parse, or imports something that does not exist, is refused with 400 and the edge's reason; nothing is created.
  • Invoking from the API or dashboard is a test call: it forwards method, path, headers and body, waits up to 10 seconds and returns the status, headers and the first 16 KB of the body. Real traffic goes to the URL and is not counted or capped yet.
  • Test calls are counted as test calls, never as traffic: test_call_count on the function, and "Function test runs" under Usage. invocation_count (requests to the URL) is null until traffic is measured.
  • No logs and no scheduled (cron) runs yet: a function runs when its URL is called.
  • Developers and above can read a function's stored source; viewers cannot.
  • Keys: a key limited to the project can create, deploy and delete its functions; a read-only key can read and test-invoke them.

Reference

SDK
const code = `export default {
  async fetch(request, env) {
    return Response.json({ hello: 'world', region: env.REGION ?? 'edge' });
  },
};`;
const { function: fn } = await hk.functions.create(project.id, { name: 'hello', runtime: 'node22', code });
console.log(fn.url);                            // https://hk-<project>--hello.harakumo.app
await hk.functions.update(fn.id, { code });     // redeploy (also picks up env changes)
const { versions } = await hk.functions.versions(fn.id);
await hk.functions.rollback(fn.id, 1);          // version 1's code, live again as a new version