Node.js handler reference
Handler contract for Coderunner Node.js functions, background jobs, and scheduled jobs.
Applies to the function, job, and schedule workload types — code you upload as a ZIP and Code Runner executes against a Node bootstrap image. For a service (any container, your own Dockerfile), see Deploy a container image instead — there's no handler contract there, just a container listening on a port.
Project structure
my-coderunner/
├── handler.js
└── package.jsonpackage.json must declare "scripts": { "start": "node handler.js" } — the bootstrap image runs CMD ["npm", "start"]. A missing start script crash-loops the container and the deployment fails.
Handler contract
const handler = async (context, payload) => {
// ...
};
module.exports = { handler };| Type | Signature | Return value |
|---|---|---|
function | async (context, payload) | { statusCode, body, headers } — required. A function is a request/response HTTP handler; whatever you return becomes the response. |
job / schedule | async (context, payload) | None required — the process runs to completion and exits. Log via console.log/console.error; there's no response to return. |
payload is the JSON body supplied by the caller (function) or trigger (job/schedule, e.g. a cron firing). context is runtime-provided; no properties are documented yet beyond its presence in the signature — don't depend on undocumented context fields.
Minimal example (function)
const handler = async (context, payload) => {
try {
if (!payload?.name) {
return {
statusCode: 400,
body: { error: "Name is required" },
headers: { "content-type": "application/json" },
};
}
return {
statusCode: 200,
body: { message: `Hello ${payload.name}` },
headers: { "content-type": "application/json" },
};
} catch (err) {
console.error("Function failed", err);
return {
statusCode: 500,
body: { error: "Internal server error" },
headers: { "content-type": "application/json" },
};
}
};
module.exports = { handler };A job/schedule handler looks the same minus the return — do the work, log, and let the function end:
const handler = async (context, payload) => {
try {
console.log("Background job started");
await doSomething(payload);
console.log("Background job completed successfully");
} catch (err) {
console.error("Background job failed", err);
}
};
module.exports = { handler };External packages
Declare npm dependencies in package.json as usual; they're installed as part of the build.
{
"name": "coderunner-function",
"version": "1.0.0",
"main": "handler.js",
"scripts": { "start": "node handler.js" },
"dependencies": { "axios": "^1.7.0" }
}fetch() is available without an extra dependency for outbound HTTP calls.
Environment variables and secrets
process.env.<NAME> reads deploy-time env vars (gf deploy -e KEY=value) and injected secrets (gf deploy --secret KEY, see Secrets). Never hard-code API keys, passwords, or connection strings — and never zip a .env file.
Common status codes (function)
| Code | Usage |
|---|---|
200 | Successful execution |
201 | Resource created |
400 | Invalid or missing input |
401 / 403 | Auth required / denied |
404 | Not found |
500 | Unexpected error — don't leak exception internals in the body |
Best practices
- Always export via
module.exports = { handler }. - Use
async/await; checkresponse.okon outboundfetch()calls. - Validate
payloadbefore using it — it's caller-supplied. - Catch and log errors; don't let an unhandled rejection crash-loop the container.
- Keep secrets out of the ZIP — inject them at deploy time.
Related
- Coderunner — workload types and lifecycle
- Deploy a container image — the
servicetype instead - Python handler reference · .NET handler reference