Scheduled Functions

Run cron jobs and scheduled tasks for your applications. The platform supports HTTP functions that call your app's endpoints and Shell functions that execute commands inside your service's Docker container.

Overview

Scheduled Functions let you run recurring tasks on a cron schedule without managing your own scheduler. Each function is configured per-project in the dashboard under the Functions tab.

Every function has a name, type (HTTP or Shell), a cron schedule, the endpoint or command to execute, and an enabled flag so you can pause and resume without deleting the configuration.

Function Types

HTTP

HTTP Functions

The platform makes an HTTP request (GET or POST) to an endpoint on your running application. Your app handles the request and performs the scheduled work. Ideal for tasks like cache cleanup, sending digest emails, or syncing external data.

Shell

Shell Functions

Run a command directly inside the service's Docker container. Useful for database maintenance scripts, file cleanup, or any CLI tool available in your container image.

Cron Schedule Syntax

Schedules use standard five-field cron syntax. All times are in UTC.

Format

┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sun=0)
│ │ │ │ │
* * * * *
ScheduleExpressionDescription
Every minute* * * * *Runs once per minute
Every 5 minutes*/5 * * * *Runs every 5 minutes
Every hour0 * * * *Runs at the start of every hour
Daily at midnight0 0 * * *Runs once a day at 00:00 UTC
Weekly on Monday0 0 * * 1Runs every Monday at 00:00 UTC
Every 30 minutes*/30 * * * *Runs every 30 minutes

Creating Functions

1. Open the Functions tab

Navigate to your project in the dashboard and select the Functions tab.

2. Add a new function

Click "Add Function" and configure:

  • Name — A descriptive name (e.g., "cleanup-expired-sessions")
  • TypeHTTP or Shell
  • Schedule — Cron expression (e.g., */5 * * * *)
  • Endpoint / Command — The URL path or shell command to execute
  • Enabled — Toggle on or off without deleting the function

3. Save and verify

After saving, the function will appear in the list with its schedule and status. You can verify it is working by checking the dashboard after the first scheduled execution.

HTTP Functions

HTTP functions make a GET or POST request to an endpoint on your running application. The platform sends the request to your service's internal URL, so your endpoint does not need to be publicly accessible.

Authenticating cron requests

Your app should verify that incoming cron requests are genuine using a CRON_SECRETenvironment variable. Set this in your project's environment variables, then check for it in your handler.

Example: Next.js API route

typescript
// app/api/cron/cleanup/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function GET(req: NextRequest) {
  // Verify the request is from the platform
  const authHeader = req.headers.get("authorization");
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  // Perform your scheduled task
  const deleted = await db.sessions.deleteMany({
    where: { expiresAt: { lt: new Date() } },
  });

  return NextResponse.json({
    success: true,
    deleted: deleted.count,
  });
}

Example: Express route

typescript
// routes/cron.ts
app.get("/api/cron/cleanup", (req, res) => {
  const authHeader = req.headers.authorization;
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  // Perform cleanup...
  res.json({ success: true });
});

When configuring the HTTP function in the dashboard, set the endpoint to the path of your route (e.g., /api/cron/cleanup). The platform will resolve this against your service's domain automatically.

Shell Functions

Shell functions execute a command directly inside your service's Docker container. The command runs with the same environment variables and filesystem as your application.

Example: Database cleanup script

node scripts/cleanup-old-records.js

Example: Laravel artisan command

php artisan schedule:run

Example: Python management command

python manage.py clearsessions

Important

Shell functions run inside the existing container, so any binaries or scripts you need must be included in your Docker image. The command must exit within the execution time limit.

Limits

ResourceLimit
Concurrent functions per project2
Memory per function execution512 MB
Enable/disableFunctions can be paused and resumed without deleting configuration

Monitoring & Status

The dashboard provides real-time visibility into your function executions. Each function displays:

  • Last run time — When the function last executed
  • Last status — Whether the last execution succeeded or failed
  • Next scheduled run — When the function will next execute based on its cron schedule

If a function fails, the dashboard will show a failed status. Check your application logs for details on the failure.

Best Practices

Use CRON_SECRET for authentication

Always verify incoming HTTP function requests using a shared secret. Set a CRON_SECRET environment variable and check the Authorization header in your handler.

Keep functions idempotent

Design your functions so they can safely run multiple times without side effects. If a function is triggered twice due to a retry or overlap, it should produce the same result.

Handle failures gracefully

Wrap your function logic in try/catch blocks and return meaningful error responses. Log enough context to debug failures from the dashboard.

Respect the concurrency limit

With a maximum of 2 concurrent functions per project, avoid scheduling multiple functions at the exact same time. Stagger schedules to prevent queuing (e.g., use 0 * * * * and 5 * * * * instead of both at 0 * * * *).

Keep execution time short

Functions should complete as quickly as possible. For long-running tasks, consider breaking the work into smaller batches that run on successive invocations.

Use disable instead of delete

If you need to temporarily stop a function, disable it rather than deleting it. This preserves your configuration and execution history so you can re-enable it later.