In this guide
When you start building, "where does my backend run?" sounds like a big architectural decision. For most small products it isn't. A front end, a hosted database, a login service and a handful of small functions cover almost everything a $20-a-month product does. The question is knowing which jobs fit that shape and which don't.
What a function is
A function is a file in your project that runs when something happens, usually an incoming request. On Netlify, a web-request function exports a handler that receives a Request and returns a Response[1]. Functions can also react to platform events such as a successful deploy or a form submission[1].
export default async (req) => {
return new Response("Hello, world!")
}
export const config = { path: "/hello" }
You don't manage a machine, patch an operating system or pay for idle time. The trade-off is that each run is short-lived and starts fresh.
Jobs that fit functions well
| Job | Type | Why it fits |
|---|---|---|
| Receive a payment webhook | Request | Short, triggered by an outside service |
| Save a form to your database | Request | Validate, write, respond |
| Call a third-party API with a secret key | Request | Keeps the key off the browser |
| Generate a report or export | Background | Takes longer than a page load should wait |
| Send weekly reminder emails | Scheduled | Runs on a timer, no visitor needed |
| Clean up old records nightly | Scheduled | Quick, periodic housekeeping |
Background functions for longer jobs
A normal function should answer quickly, because someone is waiting. For work that takes longer, Netlify's background functions return an immediate 202 response and keep running for up to 15 minutes[2]. They're available on the credit-based Free, Personal and Pro plans[2].
Two things to design for:
- The visitor doesn't get the result directly. Write it to your database or send an email, then let the page check for it.
- Failures are retried: after one minute, then again two minutes later[2]. Make the job safe to run twice, so a retry doesn't send two emails.
Scheduled functions for timers

Scheduled functions run on a cron schedule, evaluated in UTC, with shortcuts such as @daily and @hourly; they're available on all Netlify plans[3]. Things worth knowing before you rely on one:
- They have a 30-second execution limit; longer work should hand off to a background function[3].
- They run on schedule only on published deploys, not previews or branch deploys[3].
- They can't be called by URL and don't accept POST data[3].
Hypothetical example
A reminder product sends weekly emails to 4,000 clients. A scheduled function wakes every Thursday, finds who needs a reminder, and hands the list to a background function, which sends in batches and records each send. If it fails halfway and retries, the records stop anyone getting two emails.
Where functions bite
- CPU and time limits. Image processing, PDF generation and AI calls can be slow. On Cloudflare's free Workers plan, each request gets 10 ms of CPU time[4], which rules out heavier work there.
- Cold starts. An idle function can take a moment to start. Usually fine; noticeable on rarely used endpoints.
- Database connections. Many short runs opening database connections can exhaust a database's connection limit. Use your database's connection pooling or HTTP-based client.
- Persistent connections. Live chat, multiplayer and real-time dashboards need long-lived connections. Netlify points to a separate offering for long-lived backends with WebSockets[1], and many teams use a hosted real-time service instead.
What it costs
Function usage is metered differently by each host: Netlify counts compute at 10 credits per GB-hour and web requests at 2 credits per 10,000[6]; Vercel bills invocations and active CPU beyond Pro's included credit[5]; Cloudflare's paid Workers plan starts at $5 a month with 10 million requests included[4]. For a small product with short functions, the cost is usually small; the risk is a bug that loops. Set alerts. See the hosting comparison.
Signs you've outgrown functions
Functions are enough when
- Most work finishes in seconds
- Longer jobs fit in background functions
- Real-time features come from a hosted service
A server earns its place when
- You need persistent connections you control
- Jobs regularly run longer than background limits
- A library or tool needs a full machine
Even then, you rarely move everything. Keep the front end and simple functions where they are, and add one small server for the job that needs it.
Mapping a real product
Hypothetical example
A receipt-reminder product for bookkeepers, mapped job by job:
| Job | Where it runs | Notes |
|---|---|---|
| Sign-in and sessions | Login service | No code of your own beyond the integration |
| Dashboard data | Database, read from the front end with access rules | Row-level rules keep customers separate |
| Client uploads a receipt | Request function | Checks the link, stores the file, records it |
| Payment webhook | Request function | Verifies the signature, updates the plan |
| Thursday reminders | Scheduled function, then background function | Scheduled job finds who's due; background job sends in batches |
| Monthly PDF summary | Background function | Generates and emails the report |
Nothing on that list needs a server you manage. The product runs on a static front end, a hosted database, a login service and five functions.
Habits that keep functions reliable
- Keep each function small, doing one job. It's easier to test and retry.
- Make jobs safe to repeat: record what's been done, and check before doing it again.
- Log one line per run with what happened and how long it took.
- Put secrets in environment variables, never in the function's code.
- Time-box external calls, so one slow API doesn't hold up everything.
Where function setups go wrong
- Doing slow work in a request function while the visitor waits.
- Non-idempotent jobs that send duplicates when retried.
- Testing a scheduled job on a preview and assuming it ran.
- Opening a new database connection per run without pooling.
List every backend job your product does, and put each in one column: request, background or scheduled. If anything doesn't fit, that's the one job to think about a server for.
Sources
Checked 14 November 2026. Numbers in brackets in the text point to these sources.



