Background jobs without per-run pricing: Trigger.dev + Coolify
How we run PideAí's jobs on self-hosted Trigger.dev in Coolify, deployed from GitHub Actions: retries, cron and logs at a fixed cost.
How much will tomorrow’s cron job cost you? If your jobs run on a service that charges per run, you won’t know until the invoice shows up.
Every backend gets to this point eventually: some work can’t wait for a user to click something. At PideAí that meant three things: syncing the exchange rate, sending WhatsApp reminders and cleaning up abandoned carts.
The two usual options
The first is to build it yourself with Redis, a queue, workers, retries and something to alert you when it fails. It works, but now you’re maintaining one more piece of infrastructure.
The second is to pay for a managed service. You don’t maintain anything, but every run adds up. A job every 30 minutes is 1,440 runs a month, and that’s just one job.
We wanted full control, little maintenance and a cost that stays put. We found it in self-hosted Trigger.dev, Coolify and GitHub Actions.
What Trigger.dev handles
Trigger.dev is an open source framework for writing, running and monitoring jobs in TypeScript. Out of the box it does what you’d otherwise end up building yourself: it retries failed tasks, schedules them with cron, keeps the logs for every run and lets one task trigger another so you can build complete workflows.
You can also host it yourself. The data stays on your server and you don’t pay per run. You pay for the server, which you already had.
A real example: the BCV rate, every hour
PideAí sells in Venezuela, so prices depend on the Central Bank of Venezuela (BCV) exchange rate. This task fetches it every hour and updates the store:
import { schedules } from '@trigger.dev/sdk/v3';
export const syncExchangeRates = schedules.task({
id: 'sync-bcv-rates',
cron: '0 * * * *', // every hour
run: async () => {
const rates = await fetchBCVRates();
await updateStoreRates(rates);
console.log('Exchange rates synced successfully.');
},
});
If the BCV doesn’t respond, Trigger.dev retries on its own, and the dashboard shows every run along with its result.
How it gets to production

The Trigger.dev instance (the API and the workers) runs on Coolify, an open source, self-hosted alternative to Heroku or Vercel. That’s where we spin it up and manage it like any other app on the server.
GitHub Actions takes care of deploys. Every push to main runs npx trigger.dev deploy and the jobs update without anyone touching anything. The API URL and the token live as repository secrets, so the deploy always targets our instance and never Trigger.dev’s cloud.
What else runs there
Besides the exchange rate, it handles a daily cleanup of expired sessions, low-stock alerts every 30 minutes and scheduled WhatsApp campaigns.
Adding a new job is just a matter of writing the task and pushing it, and the bill stays the same.
Is it a good fit for you?
If you already have a server and run more than a handful of jobs, probably yes. If you don’t want to manage anything, a managed service is still a reasonable choice, since what you’re paying for is not having to maintain it.