Skip to main content

Automate workflows

Automations written in real code

Cron jobs, queue workers and multi-step workflows in JavaScript or TypeScript, with a database in the same project.

No credit card · Data stored in the EU

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.

index.js
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();

Workflow state is stored in the database, so you can inspect every run.

Questions about automations

Common questions about building with Codehooks.

How do I schedule a job?
Call 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?
In a workflow, each step can have its own 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?
Enqueue one job per record and let workers process them in parallel. 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?
If a prebuilt connector already does what you need, those tools are often quicker. Codehooks has no connector catalogue (you call APIs yourself), so it suits automations with custom logic, state across runs, or a database and API in the same project.

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.