Templates / Database keep-alive
Keeping an idle database awake
Serverless and free-tier databases suspend after an idle window. The next request pays for the resume — several seconds, sometimes more — and it is always a real user who pays it.
The recipe
- Request
- GET https://{{domain}}/api/health/db
- Schedule
- Every 4 hours (0 */4 * * *)
- Timeout
- 30s
- Attempts
- 3
- Counts as success
- 200
You supply
- Your domain
- example.com
Host only — no https:// and no trailing slash.
Why this job exists
Auto-suspend is how free tiers are affordable. Neon, Supabase, PlanetScale, Render and most others pause compute after a few minutes with no connections, and bill you for the storage alone. Resume is quick as these things go, but it is measured in seconds, and it lands on whoever happens to arrive first.
For a side project that is a fair trade. For anything with users it is the worst kind of latency: rare, unreproducible, and concentrated on your least engaged visitors — the ones arriving at a quiet hour, which is exactly when the database is asleep.
A small query on a slow cadence resets the idle timer for a fraction of the compute you would otherwise buy by upgrading.
Setting it up
Point this at an endpoint that genuinely reaches the database. A route that returns a static "ok" without opening a connection keeps nothing awake, and it is the mistake that makes this recipe look like it is working when it is not:
A health route that actually touches the database
export async function GET() {
const started = Date.now();
await db.query('select 1');
return Response.json({
database: 'ok',
latencyMs: Date.now() - started,
});
}Reporting the latency turns the run history into a record of whether the keep-alive is working: a run in single-digit milliseconds found the database awake, one in the thousands found it asleep and just paid for the resume itself.
Checking it actually works
- Compare the reported latency across runs. Consistently low means the instance is staying up.
- Check your provider’s dashboard for compute hours — they should now be continuous rather than spiky.
- Read your provider’s actual idle timeout and set the cadence below it. Four hours is a safe default but it is not universal.
Where it goes wrong
The cadence is longer than the idle timeout
If the database suspends after five minutes and you ping every four hours, you have added load and fixed nothing. Match the cadence to the documented timeout, with margin. Some providers suspend far more aggressively than the marketing suggests.
Keeping a metered instance awake costs money
On usage-billed compute this converts an idle database into a permanently running one. Check what continuous compute costs on your plan before assuming this is free — on some providers, upgrading is cheaper than never sleeping.
The endpoint uses a pooled connection that is also asleep
Connection poolers can answer without waking the compute behind them. If latency never improves, query through the direct connection string for this check.
Questions
Does this violate the provider’s terms?
Generally no — you are making ordinary queries against your own database. Some free tiers do explicitly prohibit keeping instances artificially alive; read yours, because the enforcement is usually suspension of the account rather than a warning.
Is select 1 enough?
For waking compute, yes. If you also want to know the database is genuinely usable rather than merely reachable, read one row from a real table instead.
Should I do this in production?
If production runs on a tier that suspends, the honest answer is to move off that tier. This recipe is a good bridge and a poor destination.
Running it here
This is a preset in the product, not an illustration. Pick it in the dashboard, fill in the one value above, and the job is created, scheduled and enabled — with retries, a record of every run showing status, latency and response, and an alert the first time one fails. Secret values are encrypted at rest and never rendered back.
The free plan runs 3 jobs hourly and needs no card. Where a recipe wants a finer cadence than your plan allows, it is slowed to the fastest schedule you are permitted rather than rejected.