Naijacloud
Docs

Functions

A function is one file, or a folder with an entry file, that answers HTTPS requests. No repository, framework or port. Deploy it from the CLI and it gets its own URL, reading the variables you give your project's functions.

5 min read

Functions suit the small pieces of backend code a frontend needs: a Paystack webhook, a call to an AI API with a secret key, sending an email. They are like Supabase Edge Functions, and most Supabase functions copy over as they are.

Quick start

  1. Install the CLI and log in. Once per machine.

    Terminal
    bash
    npm i -g @naijacloud/cli naijacloud login
  2. Save this as hello.ts.

    hello.ts
    ts
    export default async function handler(req: Request) { const name = process.env.GREETING ?? "world"; return Response.json({ message: `Hello ${name}` }); }
  3. Deploy it. Run this in the folder with hello.ts, with your project's name.

    Terminal
    bash
    naijacloud functions deploy hello --project <your-project>

The CLI prints the function's URL when it is live. It looks like https://<your-project>-fn.naijacloud.app/functions/v1/hello; always copy the one the CLI or the dashboard shows. The function's page in the dashboard shows its calls, errors and logs.

The CLI is naijacloud, or njc for short.

Two ways to write a function

Both are TypeScript or JavaScript, and both are saved as hello.ts (or .js).

TypeScript, Node style. Export a handler that takes a Request and returns a Response. You can use process.env, Buffer and node: modules.

hello.ts
ts
export default async function handler(req: Request) { const name = process.env.GREETING ?? "world"; return Response.json({ message: `Hello ${name}` }); }

Supabase / Deno style. Pass your handler to Deno.serve. This is the shape Supabase Edge Functions use.

hello.ts
ts
Deno.serve(async (req: Request) => { const name = Deno.env.get("GREETING") ?? "world"; return Response.json({ message: `Hello ${name}` }); });

export default { fetch } works too.

npm packages

Put a package.json next to your entry file and import packages by name, for example import { z } from "zod". The CLI uploads the folder and the dependencies are installed when the deploy builds. An import that cannot be found fails the deploy, and the version before it keeps serving, so a bad import never reaches your first call.

package.json
json
{ "dependencies": { "zod": "^3.23.8" } }

Paths

Your function sees the path with /functions/v1 taken off, so a call to /functions/v1/hello/receipts arrives as /hello/receipts. A router that expects that base path, such as Hono's basePath('/hello'), works unchanged.

Names

Function names use lower-case letters, numbers and dashes, up to 40 characters, and cannot start or end with a dash. send-receipt is a good name. Each name is unique in a project.

Read a secret

Every function in a project reads the same variables and secret files. They belong to the project's functions runtime, a service named functions-runtime. Set one from the CLI:

Terminal
bash
naijacloud env set GREETING --service functions-runtime --project <your-project>

If the project has functions in more than one environment, add --env <name>.

After the first deploy you can also set them in the dashboard: open any function and choose Edit project variables on its Overview, which opens the runtime's Variables tab.

Then read it with process.env.GREETING, or Deno.env.get("GREETING") in the Deno style. The function's Overview lists the names it can read, never the values, with a link to edit them. A changed variable applies on the next deploy.

Deleting a project's last function removes its runtime, and the runtime's variables and secret files go with it, so an empty project isn't billed. Set them again after you deploy a function there next.

Call it from your frontend

A function is public: anyone with the URL can call it. Check what you need in your code, such as a webhook signature or a token in a header.

A browser on another domain needs CORS headers. Answer the preflight and add the header to every response:

hello.ts
ts
const cors = { "Access-Control-Allow-Origin": "https://your-site.example", "Access-Control-Allow-Headers": "content-type, authorization", }; export default async function handler(req: Request) { if (req.method === "OPTIONS") return new Response(null, { headers: cors }); return Response.json({ ok: true }, { headers: cors }); }
From your site
js
const res = await fetch("https://<your-project>-fn.naijacloud.app/functions/v1/hello"); const data = await res.json();

View logs

Open the function in the dashboard and choose Logs. Each call shows its request line (method, path, status and how long it took) above the lines your code printed with console.log, console.warn or console.error. With Argus on, the same lines are in Argus too.

Moving from Supabase Edge Functions

The command is almost the same:

SupabaseNaijacloud
supabase functions deploy hellonaijacloud functions deploy hello --project <your-project>
supabase secrets set NAME=valuenaijacloud env set NAME --service functions-runtime --project <your-project>
Deno.env.get("NAME")Deno.env.get("NAME") or process.env.NAME

What doesn't carry over yet:

  • verify_jwt. Functions do not check a Supabase JWT for you. Every function is public, so check the token in your code.
  • Supabase's own variables. Supabase sets SUPABASE_URL and its keys for you. Here, set the ones your code reads with naijacloud env set.

Limits and pricing

LimitValue
Memory256 MB per function runtime
Longest run per call150 s on the Free tier, 400 s on paid tiers. A longer call returns 504.
Code size20 MB per deploy

Functions are included in your project's compute and billed in naira, with no charge per call. All of a project's functions share one runtime, which costs the same as a web service of the same size. On the Free tier it sleeps when idle and wakes on the next call, so that first call takes longer. On a paid tier it stays awake.

Related: Environment variables and the CLI.