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 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 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) │ │ │ │ │ * * * * *
| Schedule | Expression | Description |
|---|---|---|
| Every minute | * * * * * | Runs once per minute |
| Every 5 minutes | */5 * * * * | Runs every 5 minutes |
| Every hour | 0 * * * * | Runs at the start of every hour |
| Daily at midnight | 0 0 * * * | Runs once a day at 00:00 UTC |
| Weekly on Monday | 0 0 * * 1 | Runs 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")
- Type — HTTP 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
| Resource | Limit |
|---|---|
| Concurrent functions per project | 2 |
| Memory per function execution | 512 MB |
| Enable/disable | Functions 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.