cloadyDocs
Docs3 min read

Serverless Functions

Run an HTTP service only while requests come in. It sleeps when idle, wakes on the next request and scales out under load, set up in your compose file.

A function is an HTTP service that runs only while requests come in. Five minutes after its last request Cloady stops its container, and the next request starts it again. Under load it scales out to as many as five copies. One compose setting turns a service into a function: deploy.replicas: 0.

Mark the service

Give the service that answers your app's address replicas: 0 under deploy:

YAML
services:
  api:
    build: .
    ports:
      - "3000"
    deploy:
      replicas: 0

Both of these must hold:

  • deploy.replicas is 0.
  • The first entry under ports: is an HTTP port, such as "3000" or "8080:3000". A port ending in /tcp or /udp, or one Cloady treats as a database, cache, queue, mail or game port (5432, 6379, 25, …), is raw TCP, and raw TCP can't wake a container.

With build: ., Cloady builds the service from your code, with Railpack or with your Dockerfile when there is one, and sets PORT to the container port, so an app that listens on $PORT needs no changes. A service that runs an image: works the same way.

Deploy it

Deploy it like any other compose app: paste the repository into the deploy field, drop the folder on it, or use the CLI:

Terminal
cloady deploy github.com/acme/api --type git

The function starts asleep.

Call it

Open the app's address. The first request after a sleep waits while a copy starts, and is answered once the container accepts connections on its port. While the function is awake, requests go straight through. The app's custom domains wake it too.

Most of that first wait is your container's own start-up, so a small image and a quick start keep it short.

How it scales

These limits are the same for every function, and compose doesn't change them. A function:

  • wakes on a request to the app's address or to one of its custom domains;
  • sleeps five minutes after its last request;
  • scales out by one copy for every 100 requests in flight, up to five copies;
  • holds the first request after a sleep for up to 90 seconds while a copy starts, and that request fails if no copy is ready by then;
  • gives every request 90 seconds to start its response.

What can be a function

  • Only the service that answers the app's address. An app has one public hostname, answered by its first HTTP service (Services and endpoints), so publish the function with ports: and give the app's other services expose:. On any other service replicas: 0 is ignored, and the service runs one copy.
  • HTTP only. A TCP or UDP port can't wake a container, so a database or a game server never sleeps.
  • Stateless, with no volume. A function has to be able to run on any server. Requests can reach different copies, anything a copy writes to its own filesystem is gone once it sleeps, and a volume would tie every copy to the one server that holds it, so the function couldn't wake while that server is full. Keep data in a database service.

With a database

The app's other services keep running while the function sleeps, so a database it uses is already up when it wakes. Give the database expose: rather than ports:, which keeps it private to the app:

YAML
services:
  api:
    build: .
    ports:
      - "3000"
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD}@db:5432/app
    deploy:
      replicas: 0
  db:
    image: postgres:17
    expose:
      - "5432"
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: app
    volumes:
      - data:/var/lib/postgresql/data
volumes:
  data:

Add DB_PASSWORD under Environment on the app's card before you deploy.

Price

A function costs the same as the service would running all the time. Cloady prices what an app declares, not what it uses (Capacity and price), and counts a function's CPU and memory once, whether it is asleep or busy. Inside the free allowance it costs nothing either way.

Run it locally

docker compose up starts no container for a service with replicas: 0. Give it one:

Terminal
docker compose up --scale api=1

Change it later

For an app built from a GitHub repository, change replicas in the compose file and push; the next deploy applies it. Remove replicas: 0 to make the function an always-on service again. Apps created from an upload or from the catalog keep the compose file they were created with.

In the dashboard

The app reads as running while its function sleeps. Its status page shows the function as Idle, and Monitor's uptime check leaves it asleep.


Next: Core Concepts covers services, endpoints and pricing, and the CLI Reference covers cloady deploy.

On this page