Skip to content

Functions with config.background: true run with the 60s synchronous timeout when deployed via netlify deploy #8354

Description

@robnewton

Describe the bug

A v2 function that declares background mode in-source with export const config = { background: true } and is deployed with netlify deploy --no-build ends up half-applied:

  • The Netlify API reports the function with invoke_mode: "background".
  • Callers get the documented instant 202 Accepted.
  • But execution is killed at exactly the 60-second synchronous limit (Duration: 60000 ms in function logs, the function body never completes), and AWS Lambda async-retries the killed invocation twice, so the body also runs 3 times.

An identical function using the legacy -background filename suffix gets the real 15-minute background budget and completes normally, on the same site, same deploy, same command.

Reproduced identically on netlify-cli 26.1.0 (first version whose bundler supports config.background, zip-it-and-ship-it 14.6.0) and 26.2.0 (latest). Runtime nodejs20.x, us-east-2, paid team plan (background functions enabled, proven by the suffixed control running >90s on the same site).

Observed (both probes are identical 90s sleepers that log START/END, fired at the same moment):

[probe-bg-config]            02:46:52.727Z INFO Duration: 60000 ms   Memory Usage: 113 MB
[probe-bg-config]            02:46:52.743Z INFO PROBE probe-bg-config START 2026-07-23T02:46:52.743Z

[probe-bg-suffix-background] 02:46:52.815Z INFO Duration: 90335 ms   Memory Usage: 104 MB
[probe-bg-suffix-background] 02:46:52.822Z INFO PROBE probe-bg-suffix-background START 2026-07-23T02:46:52.822Z
[probe-bg-suffix-background] 02:48:22.822Z INFO PROBE probe-bg-suffix-background END 2026-07-23T02:48:22.822Z

probe-bg-config (config only): killed at 60s, END never logs, 2 async retries follow. probe-bg-suffix-background (suffix): END at exactly START+90s. Same result on both CLI versions.

Expected: per the Background functions docs and the configuration defaults table, config.background: true should grant the 15-minute background execution limit. A function the API itself reports as invoke_mode: background and that 202-acks callers should not run under the 60s synchronous limit. The two declaration mechanisms should not diverge.

This is nasty in production: every observable signal (dashboard, API, 202s) says "background", so nothing errors at the caller. The function is silently killed mid-work and silently re-run twice, applying partial effects up to 3 times for non-idempotent work.

Possibly related internals: config.background only entered the in-source-config schema in zisi 14.6.0 (CLI 26.1.0); older CLIs silently strip it. netlify.toml [functions.<name>] background = true is dropped by normalizeFunctionsConfig at every version, so the toml route is no workaround. We've also observed in-source path routes being bundled and uploaded but 404ing on --no-build deploys (they only take effect via the build-pipeline manifest). It looks like CLI deploys upload enough for registration/routing (invocationMode) but timeout provisioning never switches to the background budget.

Workaround: the -background filename suffix (directory + entry file) behaves correctly at every CLI version.

Steps to reproduce

  1. Create a project with two identical dependency-free v2 functions that sleep 90s:

    functions/probe-bg-config/probe-bg-config.ts:

    export const config = { background: true };
    
    export default async () => {
      console.log(`PROBE probe-bg-config START ${new Date().toISOString()}`);
      await new Promise((resolve) => setTimeout(resolve, 90_000));
      console.log(`PROBE probe-bg-config END ${new Date().toISOString()}`);
      return new Response('ok', { status: 200 });
    };

    functions/probe-bg-suffix-background/probe-bg-suffix-background.ts: identical body (suffix variant also keeps the config export).

  2. Deploy without the build pipeline:

    npx -y netlify-cli@26.2.0 deploy --no-build --site <site> --dir public --functions functions --alias probe
  3. Confirm both functions registered as background:

    curl -s -H "Authorization: Bearer $NETLIFY_AUTH_TOKEN" \
      "https://api.netlify.com/api/v1/sites/$SITE_ID/functions"
    # both report "im": "background"
  4. Invoke each once — both return 202 in ~0.2s:

    curl -X POST "https://probe--<site>.netlify.app/.netlify/functions/probe-bg-config"
    curl -X POST "https://probe--<site>.netlify.app/.netlify/functions/probe-bg-suffix-background"
  5. Wait ~2.5 minutes, then read the logs:

    npx -y netlify-cli@26.2.0 logs --source functions \
      --url https://probe--<site>.netlify.app --since 30m
  6. See that probe-bg-config shows Duration: 60000 ms with no END line (plus 2 unrequested retry STARTs), while probe-bg-suffix-background logs END at START+90s.

  7. Optional: redeploy with netlify-cli@26.1.0 and repeat — identical results.

Configuration

[build]
  command = "pnpm --filter @hopdrive/svc-s3... build"
  publish = "public"

[functions]
  directory = "functions"

[dev]
  autoLaunch = false

(No [functions.<name>] blocks, no redirects. The deploy is --no-build, so the build section is inert.)

Environment

  • netlify-cli: 26.1.0 and 26.2.0 (both reproduce)
  • Node.js: 20.x locally and on the GitHub-hosted runner; functions runtime nodejs20.x
  • OS: macOS 14 and ubuntu-latest (GitHub Actions) — same behavior
  • Deploy: netlify deploy --no-build --site <site> --dir public --functions functions --alias <alias>

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugcode to address defects in shipped code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions