Services
Function AppComing soon
Write a function in TypeScript, JavaScript or Python and get an HTTPS address for it, with your project's variables already set.
Coming soon. This feature is coming soon. It is not available to deploy yet; this page describes how it will work.
How it works
Click Create function on the Function App card of the project's Services tab. Give it a name, pick a runtime, write the handler and click Deploy (or deploy a file from your terminal, below). We build it and it is live at https://<name>-<project>.<apps domain> in about a minute.
- Every request to the address, with any method and path, calls your handler.
- The project's variables are set for it:
DATABASE_URL,REDIS_URL, theS3_*storage keys,AUTH_*,EMAIL_*,JOBS_*and your custom variables, as on the Environment tab. They are read each time the function starts, so new services and new passwords are picked up. - After 10 minutes without requests it stops. The next request starts it again in about a second: it is held while the function starts and then sent on, with its method and body (a 307 redirect to the same address).
- You pay for requests and the time they take, not for the hours it waits.
TypeScript and JavaScript
Node.js 24. Put the handler in index.ts (or index.js) as the default export. It gets a standard web Request and returns a Response; a string or an object is sent for you, as text or JSON. TypeScript runs as is: types are removed, so use plain syntax (no enum or namespace).
import pg from "pg";
// Created once per start, and reused by every request.
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL, max: 5 });
export default async function handler(request: Request): Promise<Response> {
const url = new URL(request.url);
if (request.method === "POST") {
const { title } = await request.json();
const { rows } = await pool.query("insert into todos (title) values ($1) returning *", [title]);
return Response.json(rows[0], { status: 201 });
}
const { rows } = await pool.query("select * from todos order by id desc limit $1", [url.searchParams.get("limit") ?? 20]);
return Response.json(rows);
}{
"dependencies": {
"pg": "^8.13.0"
}
}Dependencies are installed with npm install on every deploy. The handler is an ES module unless package.json sets another type.
Python
Python 3.13. Define handler(request) in main.py, plain or async. request has method, path, query (a dict), headers (lowercase keys), body (bytes), text and json(). Return a dict or list (sent as JSON), a string, bytes, None (204), or a tuple of the body, the status and a dict of headers.
import os
import psycopg
def handler(request):
if request.method == "POST":
title = request.json()["title"]
with psycopg.connect(os.environ["DATABASE_URL"]) as db:
row = db.execute("insert into todos (title) values (%s) returning id", [title]).fetchone()
return {"id": row[0], "title": title}, 201
return {"hello": request.query.get("name", "world")}psycopg[binary]==3.2.3Call it
curl "https://api-my-project.example.app/todos?limit=5"
curl -X POST https://api-my-project.example.app/todos -H "content-type: application/json" -d '{"title":"Ship it"}'- The address is public. Check a token or a signature in the handler for anything private, for example a header your app sends with a secret from its own variables.
- Answer CORS yourself when browsers call it from another site: return the
access-control-allow-*headers, and answerOPTIONS. - An uncaught error answers 500 and is written to the Logs tab. A request that takes longer than the plan's timeout answers 504.
- Clients that do not follow redirects (curl without
-L) may see the 307 on the first request after the function slept.
Deploy from your terminal
You can also deploy a file without opening the dashboard. Create function shows these steps with your project id filled in, under Deploy from terminal.
export default {
fetch: (request: Request) => new Response("Hello world"),
};export CLOUDHIKE_API_KEY="icu_..."curl -X PUT "https://cloudhike.dev/api/v1/projects/<project id>/functions/hello?file=hello.ts" \
-H "Authorization: Bearer $CLOUDHIKE_API_KEY" \
--data-binary @hello.ts- The last part of the address is the function's name. Run the command again to deploy a change; use another name to add another function to the project.
- The file's extension picks the runtime:
.ts,.jsor.mjsfor Node.js,.pyfor Python. A function's runtime cannot change once it exists. - Add
&environment=developmentto deploy to another environment, and&size=smallto choose a size. GETthe same address for the function's status and url.GET .../functionslists the project's functions.- A JSON body works too:
{"runtime": "node", "code": "...", "dependencies": "..."}withcontent-type: application/json.
Change, test and deploy
Edit the code on the function's Code & test tab and click Save and deploy; the running version keeps answering until the new one replaces it. The Test panel below it sends a request (any method, path, headers and body) to the deployed function and shows the status, time and response. Test requests are billed like any other. The row of names under the function's title moves between the project's functions, and New function adds one. Settings changes the size and adds variables of its own, which win over the project's. Logs shows the last 200 lines it wrote. AI editors connected through the MCP server can create and update functions with the deploy_function tool.
Limits and pricing
| Free | Pro | |
|---|---|---|
| Functions per project | 2 | No limit |
| Sizes | Micro (256 MB) | Micro to Large (2 GB) |
| Longest request | 30 seconds | 5 minutes |
| Each month, per function | 100,000 requests and 25,000 GB-seconds, then it stops until the next month | 100,000 requests and 25,000 GB-seconds included, then $0.40 per million requests and $0.012 per 1,000 GB-seconds |
| Code | 512 KB | 512 KB |
- GB-seconds are the time requests take, from arriving to the last byte of the answer, at the function's memory size: one second at 256 MB is 0.25 GB-seconds.
- Usage is counted every few minutes, so a Free function can go a little past its month before it stops. Upgrading to Pro starts it again.
- Requests and compute are charged from your credits every hour, like email and background jobs. The function's page shows this month's use.
- The function's disk is read-only;
/tmpcan be written, is kept in memory and is emptied when it stops. Keep data in Postgres, Redis or Storage.
Use with AI
Let your coding agent write and deploy a function for your backend.
- 1
Open a terminal in your app's folder and start Claude Code.
claude - 2
Paste the prompt below and press Enter. Approve the file edits and commands it asks about.
- 3
Optional: save a short note about CloudHike.dev in CLAUDE.md so every session knows about it.
Read https://cloudhike.dev/docs/md/functions. Write a CloudHike.dev function for this app's API: an index.ts default export that takes a Request and returns a Response, using DATABASE_URL from process.env, with its package.json dependencies. Deploy it with the deploy_function MCP tool, wait for it with wait_for_services, and call it from the app at the url it returns.
Replace the placeholders in <angle brackets> before sending. Always review what the agent changes.
