Automation
Onboarding-orkestratie: n8n vs Make vs Cloudflare Workers
Drie orchestrators, één wekelijkse load van 3.200 flows, één HR-dienstverlener uit Apeldoorn. We meten cost per run, AVG-logging en wie om 04:00 opneemt.

Het is 04:11 op een dinsdag in Apeldoorn. PagerDuty piept. Een n8n self-hosted container heeft 8 GB RAM opgevreten, de OOM killer heeft zijn werk gedaan, en 312 onboarding-flows hangen achter een dode worker. De eerste sync naar Workday draait om 06:00. Iemand moet binnen anderhalf uur achter een laptop zitten, anders lopen 312 nieuwe medewerkers op hun eerste werkdag binnen zonder laptop, zonder toegangspas en zonder loonadministratie.
Dat telefoontje bepaalde de stack. De HR-dienstverlener voor wie we het bouwden draait ongeveer 3.200 nieuwe-medewerker flows per week over ruim veertig klantaccounts. Elke flow raakt zes tot elf systemen: AFAS, Nmbrs, Microsoft 365, de Workday-tenant van de klant, een CV-screening model, een achtergrondcheckleverancier, een contract-signing tool en een hardware-bestelportaal. We hebben drie orchestration-lagen tegen dezelfde load getest: n8n self-hosted, Make.com Enterprise en een custom stack van Cloudflare Workers met Hono. Dit kwam eruit.
De vorm van de workload
Voordat een tool-vergelijking eerlijk is, moet je de workload op papier zetten. Bij ons zag die er zo uit:
- 3.200 onboarding-starts per week, met een duidelijke maandagpiek (640 tot 720 starts tussen 08:00 en 11:00 CET).
- Elke start waaiert uit in 7 tot 14 child jobs over 72 uur, dus de feitelijke job count ligt dichter bij 32.000 per week.
- Ongeveer 4% van de CV's wordt door een model gefilterd voordat een mens ze ziet. Die afwijzingen moeten een audittrail opleveren die een AVG-functionaris kan lezen.
- Drie downstream API's (AFAS, de Workday-tenant, de achtergrondcheckleverancier) hebben harde rate limits en tail latencies van 30 tot 90 seconden.
- Het team dat dit moet onderhouden bestaat uit twee mensen. Geen van beiden is fulltime platform engineer.
Dat laatste punt telt zwaarder dan de andere bij elkaar. Een stack die een eigen SRE op stand-by nodig heeft, is verkeerd voor een bedrijf van 24 mensen, hoe goed de cost per run op een spreadsheet ook oogt.
Cost per run op dezelfde load
We hebben elke optie twee weken laten draaien op een gespiegeld stuk productie-traffic (ongeveer 400 starts per week, uitwaaierend naar ruwweg 4.000 jobs). De cijfers hieronder zijn wat we hebben gemeten, niet de listprijs.
Make.com Enterprise. Make rekent af op operations: grofweg één operation per module-call. Onze gemiddelde flow at end-to-end 47 operations, met de CV-screening branch en de AFAS retry-loop als grootste verbruikers. Na het samenvouwen van iterators kwamen we uit op zo'n 12 operations per job. Bij 32.000 jobs per week zaten we in de hoogste Enterprise-staffel. Effectieve cost lag rond de €0,011 per run, plus €1.700 per maand aan vaste seats. De pricing staat openlijk op de Make pricing-pagina, maar het echte getal leer je pas kennen nadat je je eigen operations-teller hebt geïnstrumenteerd.
n8n self-hosted. Self-hosted n8n op één Hetzner CPX31 (€16 per maand) plus een managed Postgres (€25 per maand) is bijna gratis op kleine schaal. Bij onze load moest de worker opgesplitst worden, dus we draaiden drie workers achter een queue-mode setup. De infrastructuur kostte alles bij elkaar zo'n €110 per maand. Cost per run, naïef gerekend, lag rond de €0,0009. Dat getal is een leugen totdat je de on-call uren erbij optelt: gedurende de tweewekelijkse pilot zaten we elf engineer-uren in n8n zelf (worker-restarts, version bumps, één keer een Postgres connection pool tunen). Tegen €120 per uur all-in is dat nog eens €0,0041 per run. Echte kosten: €0,005. De queue-mode documentatie is duidelijk, maar gaat ervan uit dat je iemand hebt die hem leest.
Cloudflare Workers + Hono. Een Worker invocation op het Paid-plan kost $0,30 per miljoen requests bovenop de inbegrepen staffel, en Durable Objects voegen een kleine per-request charge toe voor de stateful flow coordinator. We hebben één Hono-Worker per integratie geschreven en één Durable Object class per onboarding-flow. Bij onze load was de Cloudflare-rekening €38 per maand. De R2-bucket die we gebruikten voor CV-blobs en audit logs telde er nog €4 bij op. Engineeringtijd, na de eerste maand, was praktisch nul. Cost per run: ongeveer €0,0003.
Het kostenverhaal kantelt afhankelijk van wat je telt. Kijk je alleen naar de factuur, dan wint Workers met een factor tien. Tel je de engineer-uren mee die het platform vraagt, dan wint Make de eerste drie maanden en Workers daarna.
AVG-houdbare logging als een model een CV afwijst
Artikel 22 AVG geeft een kandidaat recht op uitleg wanneer een geautomatiseerd systeem hem of haar wezenlijk raakt. Een model dat een CV filtert voordat een mens hem ziet, is precies dat. De artikeltekst staat op gdpr-info.eu. Kort gezegd: je moet voor elke afwijzing de input, de modelversie, de score, de drempelwaarde, de beslissing en de menselijke reviewer (als die er is) loggen, en lang genoeg bewaren om de beslissing te kunnen verdedigen maar niet langer dan nodig.
Op die eis lopen de drie stacks het sterkst uiteen.
Make bewaart execution logs 30 tot 90 dagen, afhankelijk van het plan, en het log-formaat is van hen, niet van jou. Voor een AVG-houdbaar spoor moet je elk rejection-event mirroren naar je eigen opslag. Wij deden dat met een Make HTTP-module die postte naar een Workers-endpoint dat wegschreef naar R2. Dat werkt, maar je hebt nu twee systems of record en een sync-correctness probleem.
n8n houdt execution data in jouw Postgres. Jij bent eigenaar, jij kunt querien, jij kunt het bewijzen. De adder zit in retentie. Na acht maanden was onze executions-tabel 184 GB en groeide door. We probeerden oude rijen te deleten op kandidaat-ID en leerden wat de meeste teams op de harde manier leren: op schaal kun je in Postgres niet echt deleten. Een DELETE tegen een tabel van 200 GB schrijft ruwweg zijn eigen omvang aan WAL, blaast de heap op met dode tuples die VACUUM vervolgens moet opjagen, en knokt met de queue workers om row locks. De Postgres-documentatie over table partitioning spelt het alternatief uit: partitioneer de executions-tabel per maand, drop de oude partitie met DROP TABLE, en het delete-probleem wordt een metadata-wijziging. Lijn het AVG-bewaartermijn uit op de partitiegrens en de hoofdpijn verdwijnt.
Workers + R2 omzeilt het probleem anders. Elk rejection-event wordt een object met een key als avg-log/2026/06/16/<candidate-uuid>.json. R2 lifecycle rules laten de prefix na 24 maanden vervallen. Geen tabel om te vacuumen en geen log-formaat dat je niet zelf in handen hebt.
Als je orchestrator je AVG-relevante logs in zijn eigen database bewaart, is jouw bewaarbeleid zijn bewaarbeleid. Mirror het afwijzingsspoor op dag één naar opslag die je zelf beheert, niet op de dag dat de advocaat van de kandidaat je schrijft.
De 04:00-vraag
Elke vergelijking van orchestration-tools komt uiteindelijk op hetzelfde punt uit: zondag om 04:00, er is iets stuk, wie neemt de telefoon op en wat leest die persoon?
Bij Make Enterprise is het antwoord deels Make. Hun statuspagina dekt hun platform en hun support reageert binnen het SLA-venster. Maar de failure mode die in de praktijk het vaakst voorkomt (een third-party API die rate-limit, een misvormde payload, een credential-rotatie die misging) is niet hun probleem. Jouw runbook moet er nog steeds zijn.
Bij n8n self-hosted ben jij het antwoord. De worker is jouw worker. De Postgres is jouw Postgres. Als de worker om 04:11 OOMt, raakt geen leverancier dat. We hebben geleerd om een harde memory limit op de worker-container te zetten, een restart policy unless-stopped, en een apart proces dat de queue leegt als de worker binnen vijf minuten twee keer omvalt. Dat werkt. Het moet ook geschreven, getest en in handen zijn van iemand wiens naam in een kalender staat.
Bij Workers is de runtime Cloudflare's probleem. We zijn nog nooit gepiept voor een Worker invocation die niet liep. Wel voor onze eigen code die gooide, voor een Durable Object dat tegen een storage limit aanliep die we niet hadden voorzien, en voor een upstream API die HTML in plaats van JSON teruggaf. De runbook wordt korter omdat het substraat er niet meer in staat.
Waar elke stack daadwerkelijk wint
Geen van deze tools is slecht. Ze winnen verschillende gevechten.
Make Enterprise wint wanneer het team dat de flows onderhoudt niet technisch is, de integraties van de plank komen, en cost per run niet de bindende factor is. Voor een marketing-ops team dat Salesforce-naar-HubSpot syncs op laag volume automatiseert, is Make het juiste antwoord en zeggen we dat ook.
n8n self-hosted wint wanneer je één engineer hebt die infrastructuur leuk vindt, de flows complex genoeg zijn voor branching en custom nodes, en je de data op je eigen bakken wilt. Het is een goede middenweg voor een bedrijf van 50 tot 200 mensen met één degelijk platform-iemand.
Cloudflare Workers + Hono wint wanneer cost per run telt, het team dat de code schrijft thuis is in TypeScript, en de orchestration meer code is dan plaatje. Voor 32.000 jobs per week met harde latency- en AVG-eisen is dit het antwoord waar we 's nachts niet wakker van liggen. De Hono-framework bovenop Cloudflare Workers maakt de developer experience oprecht prettig.
Wat we hebben opgeleverd
Voor deze klant leverden we de Workers-stack op, met één concessie: het CV-screening model zelf draait op een aparte container achter een queue, omdat een 7B model cold-starten in een Worker in 2026 nog steeds geen goed idee is. De orchestration, het audittrail, de retry-logica en de fan-out wonen allemaal in Workers. Make staat nog in het schema, maar alleen als het oppervlak waar de twee niet-technische operations leads klant-specifieke uitzonderingsflows in bouwen en bewerken. Zij krijgen de plaatjes-bouwer, wij krijgen de runtime.
Eén concreet patroon uit de bouw: elke onboarding-flow is één Durable Object instance gekeyed op kandidaat-UUID. State transitions zijn expliciet. De hele coordinator past in zo'n 900 regels TypeScript.
import { Hono } from 'hono'
import { DurableObject } from 'cloudflare:workers'
type FlowState =
| 'cv_received'
| 'cv_screened'
| 'cv_rejected'
| 'contract_sent'
| 'contract_signed'
| 'systems_provisioned'
| 'done'
interface Env {
FLOWS: DurableObjectNamespace
AUDIT: R2Bucket
}
function transition(state: FlowState, event: { type: string }): FlowState {
if (state === 'cv_received' && event.type === 'screened_pass') return 'cv_screened'
if (state === 'cv_received' && event.type === 'screened_fail') return 'cv_rejected'
if (state === 'cv_screened' && event.type === 'contract_sent') return 'contract_sent'
if (state === 'contract_sent' && event.type === 'contract_signed') return 'contract_signed'
if (state === 'contract_signed' && event.type === 'provisioned') return 'systems_provisioned'
if (state === 'systems_provisioned' && event.type === 'done') return 'done'
return state
}
export class OnboardingFlow extends DurableObject<Env> {
async advance(event: { type: string; payload: unknown }) {
const state = (await this.ctx.storage.get<FlowState>('state')) ?? 'cv_received'
const next = transition(state, event)
await this.ctx.storage.put('state', next)
await this.ctx.storage.put(`event:${Date.now()}`, event)
if (next === 'cv_rejected') await this.writeAvgLog(event)
return next
}
private async writeAvgLog(event: unknown) {
const day = new Date().toISOString().slice(0, 10)
const key = `avg-log/${day}/${this.ctx.id.toString()}.json`
await this.env.AUDIT.put(key, JSON.stringify(event))
}
}
const app = new Hono<{ Bindings: Env }>()
app.post('/flow/:id/event', async (c) => {
const id = c.env.FLOWS.idFromName(c.req.param('id'))
const stub = c.env.FLOWS.get(id) as unknown as { advance: (e: unknown) => Promise<FlowState> }
return c.json(await stub.advance(await c.req.json()))
})
export default app
Toen we de orchestration-laag voor deze Apeldoornse HR-firma bouwden, was het ding waar we steeds tegenaan liepen het AVG-audittrail, niet de kost. We zijn uiteindelijk elk rejection-event in R2 gaan zetten met een datum-prefixed key, en de juridische review duurde negentig minuten in plaats van drie weken. Dat soort resultaat is hoe de meeste van onze AI-agent opdrachten er in de praktijk uitzien.
Ga je dit kwartaal een orchestrator kiezen? Schrijf eerst de workload op, in cijfers. Kijk daarna naar de cost-per-run regel, de AVG-regel en de 04:00-regel. De tool die op alle drie wint voor jouw werkelijke cijfers is degene om te shippen. De rest is een voorkeur die zich verkleedt als een mening.
Kern
Kies je orchestrator op werkelijke cost per run, AVG-houdbare logging en wie de 04:00-pager opneemt, niet op een demo van een pricing-pagina.
FAQ
Wat kost Make.com Enterprise echt bij 3.200 wekelijkse flows?
Na het samenvouwen van iterators verbruikten we zo'n 12 operations per job. Dat bracht ons in de hoogste Enterprise-staffel op ongeveer €0,011 per run, plus rond de €1.700 per maand aan vaste seats.
Kan n8n self-hosted 32.000 jobs per week aan?
Ja, in queue mode met drie workers achter een Postgres-queue. Reken op memory limits, restart policies en een partitioneringsstrategie op de executions-tabel zodat retentie-deletes werkbaar blijven.
Werkt Cloudflare Workers voor stateful onboarding-flows?
Ja, via Durable Objects. Eén instance per kandidaat-UUID maakt state transitions expliciet en houdt de runtime-zorg buiten je 04:00-runbook.
Hoe houd je CV-afwijzingslogging AVG-houdbaar?
Log voor elke afwijzing de input, de modelversie, de score, de drempelwaarde, de beslissing en de reviewer. Bewaar het in een systeem dat je zelf beheert en lijn de retentie uit op een partitiegrens, zodat deletes op schaal mogelijk blijven.
Waarom dan niet gewoon op Make blijven voor alles?
Make is uitstekend voor niet-technische teams en kant-en-klare integraties, maar bij 32.000 jobs per week met AVG-eisen klopt het plaatje van cost per run en log-ownership niet meer.