When does an automation need code?
Visual automation tools are quick for simple flows. They get harder to work with once a flow needs loops, error handling, or state that has to survive between runs (where the last sync stopped, which records failed, what has already been sent).
In Codehooks an automation is ordinary code. A cron expression schedules a function, a queue spreads work across parallel workers, and the Workflow API runs multi-step processes with state saved after each step and retries per step. The database sits in the same project, so state is a query away.
Typical uses are nightly syncs and reconciliations, email sequences, usage metering, cleanups and onboarding flows.
A three-step onboarding workflow
Each step hands its state to the next. If the billing call in the first step fails, it is retried up to three times before the workflow stops.
import { app } from 'codehooks-js';
const onboarding = app.createWorkflow('onboarding', 'New customer onboarding', {
createAccount: async (state, goto) => {
// call your billing API here and keep the result in state
goto('sendWelcome', { ...state, accountCreated: true });
},
sendWelcome: async (state, goto) => {
// send the welcome email
goto('notifySales', state);
},
notifySales: async (state, goto) => {
// post to your CRM or a Slack channel
goto(null, state); // done
},
}, {
steps: {
createAccount: { maxRetries: 3 }, // retry a flaky API before giving up
},
});
app.post('/signup', async (req, res) => {
const result = await onboarding.start({ email: req.body.email });
res.json(result);
});
export default app.init();
Automations you can start from
Complete examples, each with the code and a template to deploy.
Nightly reconciliation that keeps a cursor and resumes after a partial failure.
Timed email sequences defined in one config file.
Your own subscriber list with confirmed sign-ups.
Track usage per customer and send it on to billing.
Questions about automations
Common questions about building with Codehooks.
How do I schedule a job?
app.job() with a cron expression and a handler, for example app.job('0 3 * * *', ...) for 03:00 every night. The handler gets (req, res) and must call res.end() when it finishes. For one-off runs at a specific time, schedule.runAt() starts a worker later. See scheduled jobs.What happens if a step fails?
maxRetries, and state is saved between steps so a run continues from the last completed step instead of starting over. Plain queue workers are different: the queue is persistent, but what happens when your worker throws is up to your code. The Workflow API docs show both patterns.How do I process a large batch of records?
enqueueFromQuery() does that in one call from a database query, so a nightly job can find what needs doing, queue it and finish quickly. See queues and workers.Should I use this instead of Zapier, Make or n8n?
Building with a coding agent
Describe the automation to your agent and let it write the jobs, workers and workflow steps. It can deploy with coho deploy and follow the run with coho log -f, all from the terminal.
Automate your first workflow
Write a job or a workflow, deploy it, and watch it run in the logs.