Netlify scheduled function not running: 7 causes and fixes

Your Netlify scheduled function deployed fine, and then it never ran. Or it ran for weeks and quietly stopped.
There's no failed run to look at, because there was no run. Here are the causes that keep coming up, and how to check each one.
- UTC
- the time zone every Netlify cron schedule uses
- 30 sec
- max run time for a scheduled function
- published
- only published deploys run on a schedule
- Run now
- the UI button to trigger one by hand
First check: does the function show a "Scheduled" badge?
Open your site in the Netlify UI and go to the Functions page.
A correctly registered scheduled function shows a Scheduled badge and the date and time of its next run.
No badge means the schedule was never registered, so start with causes 2 and 3. A badge with a next run time means it was, so check the rest.
1. Scheduled functions only run on published deploys
Netlify runs scheduled functions on their schedule for published deploys only.
Deploy Previews and branch deploys will not trigger them automatically. If you're testing on a preview or a feature branch, nothing will ever fire there.
Fix: merge to your production branch and publish. To test a preview, open the function and press Run now.
2. The schedule isn't registered: inline config vs netlify.toml
You can set a schedule in two places. Pick one.
How to set the schedule inline
In a TypeScript or JavaScript function, export a config object with a schedule field:
// netlify/functions/nightly-report.mts
import type { Config } from "@netlify/functions";
export default async (req: Request) => {
const { next_run } = await req.json();
console.log("nightly-report started. Next run:", next_run);
// ...your job here
};
export const config: Config = {
schedule: "@daily", // 00:00 UTC
};How to set the schedule in netlify.toml
Or declare it in netlify.toml. The name in quotes has to match the function's file name without the extension.
# netlify.toml # The name in quotes must match the file name, # minus the extension: netlify/functions/nightly-report.mts [functions."nightly-report"] schedule = "0 6 * * *" # 06:00 UTC, every day
A typo in that name, or a file renamed after you wrote the config, means the schedule points at a function that doesn't exist.
3. The file isn't in the functions directory
Netlify looks for functions in netlify/functions/ by default.
If your file lives somewhere else, point Netlify at it with [functions] directory = "path" in netlify.toml, or in the Netlify UI.
If the function doesn't appear on the Functions page at all, check this first.
4. The cron runs in UTC, not your time zone
Every schedule is read as UTC. So 0 0 * * * fires at midnight UTC, which may be the middle of your afternoon.
This looks like "not running" when it's really running at an hour you didn't expect. Netlify also accepts shortcuts like @hourly, @daily and @weekly.
5. The job needs more than 30 seconds
Scheduled functions have a 30-second execution limit.
A job that grew over time (more users, more rows, a slower API) can start getting cut off before it finishes. Netlify's own advice is to hand longer work to a background function.
6. The function returns before the work is done
If you call something async without await, the handler can return while the request is still in flight.
On the Netlify forum, a Discord webhook that fired from a scheduled function kept failing with socket hang up errors. The fix was one missing await.
Fix: await every promise your job depends on, and log a line when the job finishes, not just when it starts.
7. A catch-all redirect is in the way
In another forum case, a scheduled function worked locally and did nothing in production.
The cause was a catch-all from = "/*" redirect in netlify.toml pointing at a function. Removing it fixed the schedule.
Netlify scheduled function stopped running with no errors
Sometimes every check above passes, and it still stops.
On 12 April 2026, several users on the Netlify forum reported the same thing: the dashboard still showed the next run time, but nothing fired and nothing was logged.
No one had changed any code. The fault was on Netlify's side, and support fixed it the next day.
We've seen a Netlify schedule quietly stop on one of our own sites too. We moved that job to Supabase pg_cron.
If you hit this, try a redeploy first, then open a ticket with Netlify support and include your site name and function name.
How to test a Netlify scheduled function
- Locally: run
netlify dev, thennetlify functions:invoke nightly-report. Netlify Dev won't run it on a schedule. This only checks the code works. - Deployed: open the function on the Functions page and press Run now, then read its logs there.
- Not by URL: in production a scheduled function can't be called through its URL, so a plain
curlwon't test it.
Want a second pair of eyes? Paste your function and netlify.toml into this prompt:
My Netlify scheduled function is not running on its schedule. Help me find out why, one cause at a time.
Here is my function file and my netlify.toml:
[paste both here]
Check these, in order, and tell me which one applies:
1. Is the schedule defined in exactly one place: an inline `export const config = { schedule: ... }` OR a [functions."name"] block in netlify.toml whose name matches the file name without its extension?
2. Is the file inside the functions directory Netlify actually uses (netlify/functions by default, or whatever [functions] directory points to)?
3. Is the cron expression valid, and what time does it fire in UTC versus my local time?
4. Does the handler await every async call, so the work finishes before the function returns?
5. Could the job take longer than 30 seconds? If so, show me how to move the heavy work into a background function.
6. Is there a catch-all redirect in netlify.toml (from = "/*") that points at a function?
For each problem you find, show me the corrected code. Then tell me how to confirm the fix: the "Scheduled" badge on the Functions page, the "Run now" button, and `netlify functions:invoke <name>` locally.How to get alerted when a Netlify scheduled function stops
Every cause above has the same symptom: silence. So watch for the silence.
That's a heartbeat: the job reports in when it finishes, and you get an email when a report doesn't arrive on time.
With Tell Me When Down it's one line at the end of the handler. Set TMWD_API_KEY in your Netlify environment variables first.
// netlify/functions/nightly-report.mts
import type { Config } from "@netlify/functions";
import { tmwd } from "@tellmewhendown/node";
export default async (req: Request) => {
await runNightlyReport();
// Only reached if the job above finished without throwing.
await tmwd.heartbeat("nightly-report");
};
export const config: Config = {
schedule: "@daily",
};The ping sits after the work, so a run that throws, times out, or never starts all look the same to us: a missed beat.
Vercel has its own version of these traps. See why your Vercel cron job is not running.
Know when your Netlify scheduled function goes quiet.
Join Tell Me When Down free and add one heartbeat to your scheduled function. If it stops firing, runs out of time, or throws, you get an email the first time a run goes missing, not weeks later.
spot something wrong or out of date? [email protected] — we'll fix it