Background Jobs for Vibe Coders: Ship Delayed Tasks Without Learning DevOps
You’re building fast. Cursor is writing your components, v0 is generating your UI, and you shipped your SaaS landing page before lunch. Your app is live on Vercel with a Supabase backend and Stripe billing.
Then your co-founder asks: “Can we send users a reminder if they haven’t finished onboarding after 24 hours?”
And suddenly you’re reading about message queues, Redis, worker processes, and something called BullMQ. The vibes are gone.
You Don’t Need a Queue. You Need One Line of Code.
Here’s the thing about background jobs, delayed tasks, and scheduled emails: they’re all just HTTP requests that happen later.
You already know how to make HTTP requests. You do it every time you call an API. The only difference is when.
// This sends a request RIGHT NOW
await fetch('https://your-app.com/api/send-reminder', {
method: 'POST',
body: JSON.stringify({ userId: '123' }),
});
// This sends the SAME request in 24 HOURS
await fetch('https://zeplo.to/https://your-app.com/api/send-reminder?_delay=86400&_token=YOUR_TOKEN', {
method: 'POST',
body: JSON.stringify({ userId: '123' }),
});
That’s it. Same fetch(). Same endpoint. Same body. Just prefix with zeplo.to/ and add _delay in seconds.
No Redis. No workers. No DevOps. No new concepts to learn.
What Can You Build?
Here’s a cheat sheet of common tasks and the one-liner to implement them:
Send an email later
// Send onboarding tip 2 hours after signup
await fetch(`https://zeplo.to/${APP_URL}/api/email/onboarding-tip?_delay=7200&_retry=3&_token=${TOKEN}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: user.email, tip: 'day-1' }),
});
Expire something after a timeout
// Cancel unpaid order after 30 minutes
await fetch(`https://zeplo.to/${APP_URL}/api/orders/expire?_delay=1800&_retry=2&_token=${TOKEN}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ orderId }),
});
Run a daily digest
// Set up once — runs every morning at 8am UTC
await fetch(`https://zeplo.to/${APP_URL}/api/digest?_cron=0|8|*|*|*&_retry=3&_token=${TOKEN}`, {
method: 'POST',
});
Retry a flaky API call
// Call a payment API with automatic retry on failure
await fetch(`https://zeplo.to/https://api.stripe.com/v1/charges?_retry=5&_token=${TOKEN}`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${STRIPE_KEY}` },
body: new URLSearchParams({ amount: '2000', currency: 'usd', source: tokenId }),
});
Why This Works for AI-Assisted Development
If you’re building with Cursor, Copilot, Windsurf, or prompting Claude to write your backend — you already know that the simpler the API, the better the AI output.
Compare these prompts:
❌ “Set up a BullMQ queue with Redis connection, create a worker process, add a job that sends an email in 24 hours with exponential backoff retry, and make sure the worker restarts on failure”
✅ “When a user signs up, use fetch to call zeplo.to with my email endpoint URL, a 24 hour delay, and 3 retries”
The second prompt gives you working code on the first try. Every time. Because it’s just fetch() with a URL.
There’s nothing to configure, nothing to install, and nothing for the AI to hallucinate about. Your AI assistant already knows how fetch() works.
The 5-Minute Setup
Step 1: Sign up at app.zeplo.io/register (free, 500 requests/month)
Step 2: Copy your token from the dashboard
Step 3: Add it to your .env:
ZEPLO_TOKEN=your_token_here
Step 4: Make a helper (optional but clean):
// lib/zeplo.ts
export async function scheduleRequest(url: string, options: {
delay?: number,
retry?: number,
cron?: string,
method?: string,
body?: any,
headers?: Record<string, string>,
}) {
const params = new URLSearchParams({ _token: process.env.ZEPLO_TOKEN! });
if (options.delay) params.set('_delay', String(options.delay));
if (options.retry) params.set('_retry', String(options.retry));
if (options.cron) params.set('_cron', options.cron);
return fetch(`https://zeplo.to/${url}?${params}`, {
method: options.method || 'POST',
headers: options.headers || { 'Content-Type': 'application/json' },
body: options.body ? JSON.stringify(options.body) : undefined,
});
}
// Usage
await scheduleRequest('https://my-app.vercel.app/api/send-email', {
delay: 3600,
retry: 3,
body: { userId: '123', template: 'welcome' },
});
What You’re NOT Doing
Let’s appreciate what you didn’t have to do:
Install RedisLearn BullMQ APIConfigure a worker processSet up a message brokerWrite retry logicBuild a dead letter queueMonitor worker healthHandle worker crashesManage queue backpressureDeploy a separate service
You wrote a fetch() call. Ship it.
When You Might Need More
Zeplo is perfect for: - Delayed tasks (emails, reminders, expirations) - Scheduled jobs (daily reports, cleanups, syncs) - Retry logic (payment processing, webhook delivery) - Any “do this later” pattern in a serverless app
If you ever need complex job orchestration, priority queues, or processing millions of events per second — you’ll know, and you’ll have outgrown the vibe coding phase anyway. Cross that bridge when the revenue justifies the infrastructure.
Until then, ship fast.
Zeplo adds background jobs to any app with zero infrastructure. Just fetch(). Start free →