Architecture

Self-Hosted vs SaaS Agent Infrastructure: The Real Tradeoffs

Akshay Sarode 8 min read
Direct answer

There's no universally correct choice, and anyone telling you self-hosting is always better (or hosted always is) is selling something. Self-hosting the Apache-2.0 Ujex core on your own Firebase project wins on data residency and compliance control, but you take on real ops weight, especially the mail server behind Postbox and the audit anchor job behind Audit. Hosted gets a working agent running the same afternoon, and because the core and the audit-chain verifier are both open source, starting hosted doesn't lock you out of moving to self-hosted later.

The question usually comes up around the third agent, not the first. One agent running out of a side project doesn't need much infrastructure thought: you wire up an address, maybe a webhook, and move on. By the third or fourth agent, someone asks where the audit logs actually live, who has access to the approval requests, and whether the whole setup is one vendor pricing change away from becoming a problem. That's the moment self-hosted versus hosted stops being a hypothetical and starts being a decision with a deadline attached.

Data residency and compliance control

This is the tradeoff where self-hosting has the clearest advantage, and it isn't close. If your compliance requirements say data has to stay in a specific region, under a specific cloud contract, or off shared infrastructure entirely, self-hosting the Ujex core on your own Firebase project answers that directly: it's your Firestore instance, your Cloud Functions, your project ID. You pick the region. You set the IAM policy. You can point your own auditors at your own infrastructure instead of asking a vendor for a compliance letter and hoping it covers your specific case.

A hosted setup can still meet plenty of compliance bars. For a lot of teams, reading the vendor's security documentation and deciding it's adequate is a perfectly fine trade. But for a team with a contractual or regulatory requirement that specifically says "our data, in our infrastructure," it isn't a trade at all, it's a requirement with one answer. Self-hosting is the only version of that sentence that's literally true.

The ops burden nobody puts in the pitch deck

Here's the part self-hosting pitches tend to gloss over: "self-hostable" and "easy to self-host well" are two different claims. Most of Ujex's pieces (Approvals, Recall, Governor) are ordinary Cloud Functions and Firestore collections. Standing them up on your own Firebase project is genuinely not hard: create the project, deploy the functions, point your SDK at it. That part of the pitch holds up.

Two pieces are harder, and worth naming specifically, because they're the ones people underestimate until they're already committed.

The first is the mail server behind Postbox. Giving an agent a working email address means running something that can send and receive mail reliably over time: Postfix or an equivalent MTA, OpenDKIM configured correctly, SPF and DMARC records that actually match your sending patterns, and a sender reputation you build up and then have to keep protecting. None of that is a one-time setup. DKIM key rotation, watching DMARC aggregate reports, and staying off blocklists after some agent sends a burst of retries at 3am are ongoing maintenance, not a weekend project. Get one piece of it wrong and mail silently stops arriving, which is a uniquely bad failure mode for something an agent is depending on.

The second is the audit anchor job behind Audit. The hash-chained log itself, where each entry's hash depends on the one before it so tampering breaks the chain, is something you can run yourself without much trouble. The hard part is the anchor: publishing chain roots somewhere genuinely external and tamper-resistant, on a reliable schedule, so "the log wasn't rewritten last Tuesday" is provable rather than asserted. Running that job dependably, monitoring that it actually fires, and making sure the anchor destination isn't secretly just another thing you control (which would quietly defeat the whole point) takes real, ongoing attention.

Everything else on the self-hosted side is standard ops: backups, uptime monitoring, keeping Cloud Functions patched. If your team already runs infrastructure like this, none of it is a stretch. If it doesn't, these two pieces specifically are where a self-hosted rollout tends to slip from "a day of setup" to "a recurring line item on someone's calendar."

What the two setups actually look like

Structurally, self-hosted and hosted Ujex are the same shape. Your agent code talks to the same Apache-2.0 SDKs either way. The only thing that changes is which Firebase project sits behind them.

SELF-HOSTED Your agent code (Apache-2.0 SDKs) Your Firebase project Postbox Audit Recall HOSTED Your agent code (Apache-2.0 SDKs) Ujex-managed project Postbox Audit Recall
Same SDKs, same components, different project boundary: self-hosted puts Postbox, Audit, and Recall inside infrastructure you control, hosted puts them inside a project Ujex operates for you.

That symmetry is deliberate, and it's also why moving between the two later isn't a rewrite. The interface your agent code talks to doesn't change, only what's running behind it. For a quick side by side of the tradeoffs covered above:

DimensionSelf-hostedHosted
Data residencyFull control, your Firebase project and regionInherits Ujex's infrastructure decisions
Time to first working agentDays, more if the mail server is new territoryUsually the same afternoon
Hardest pieces to run wellMail server (DKIM/SPF/DMARC) and the audit anchor jobBoth already running for you
Ongoing opsBackups, patching, uptime, mail reputationHandled by Ujex
Lock-in riskNone, it's your infrastructureLow: core and audit verifier are Apache-2.0

Time to first working agent

This is where hosted wins, and it's not a small margin. Standing up a self-hosted deployment means creating a Firebase project, deploying Cloud Functions, configuring Firestore security rules, and, if you want Postbox working from day one, getting a mail server provisioned and warmed up before you trust it with anything real. Even for a team that already knows Firebase well, that's realistically a few days of focused work before the first agent sends its first email or logs its first approval request. If the mail server piece is new territory, add more, possibly a lot more.

Hosted skips nearly all of that. Point an SDK at app.ujex.dev, get an API key, and the mail server, the audit anchor job, and the rest of the plumbing are already running. For a team that wants to know within an afternoon whether Ujex actually solves their problem before committing engineering time to the infrastructure question, that's the entire appeal. You can move to self-hosted later once you know the answer is yes. You can't get back the week you spent standing up infrastructure to test a hypothesis that turned out to be no.

Vendor lock-in, or the lack of it

The usual argument against starting hosted is lock-in: build on someone else's infrastructure and you're stuck there once the switching cost gets high enough. That argument is weaker here than it usually is, for a specific reason. The Ujex core, across the Python, Go, client-js, CLI, and MCP server SDKs, is Apache-2.0. So is the audit-chain verifier. Nothing about starting on the hosted version puts your code, your data model, or your ability to verify your own audit trail behind a proprietary wall.

Concretely: if you start hosted and later need self-hosted, whether that's a new compliance requirement, a cost inflection point, or a change in who's allowed to touch the data, you export your data and audit history and stand up the same open-source core yourself. Because the verifier is open source too, you can independently confirm the exported chain hasn't been tampered with, regardless of which mode originally produced it. That's a materially different position than being locked into a vendor's proprietary format and having to trust their export tooling on faith.

Do the math for your own setup

The honest version of this tradeoff isn't "self-hosted costs $X and hosted costs $Y," because the real number depends on your request volume, your agent count, and what an engineer-hour costs at your company. What is true in shape: self-hosted cost is mostly fixed, a baseline infra bill plus a fairly constant chunk of ops time that doesn't move much whether you're running 5 agents or 50, while hosted cost tracks more directly with how much you're actually using it.

The calculator below is not a pricing tool and doesn't reflect actual Ujex pricing. The assumptions are ones I'm stating outright, not hiding in the math: for self-hosted, a $50/month Firebase infra baseline plus $0.15 per thousand monthly requests, plus 5 hours a month of engineer time at $75/hour to keep backups, patching, the mail server, and the audit anchor job healthy, roughly regardless of agent count. For hosted, $9 per agent per month plus $1.20 per thousand requests. Change the two inputs and watch how differently the two totals move.

Try it: rough monthly shape, not a quote
$0
Self-hosted / mo (illustrative: infra + ops time)
$0
Hosted / mo (illustrative: per-agent + per-request)

At the defaults (10 agents, 50,000 requests a month) the two numbers land in the same neighborhood. Push the agent count and request volume up and the hosted number outgrows the self-hosted one, because hosted cost tracks usage while the ops-hour assumption behind self-hosted barely moves. Push both down toward a couple of agents running occasional tasks and the fixed ops-hour cost dominates the self-hosted side, making hosted look cheap by comparison. Neither number is a quote. The point is the shape, not the digits.

Mixing self-hosted and hosted

Because the core is Apache-2.0 and each piece (Postbox, Approvals, Audit, Recall, Governor, Ingress) is its own component rather than a monolith, you don't have to pick one mode for everything. A reasonable middle path: self-host the mail server if you already have deliverability infrastructure and a team that knows Postfix, but use hosted audit anchoring so you're not the one building and monitoring that job. Or the reverse: keep Audit self-hosted because your compliance requirement is specifically about the tamper-evident log living on your own infrastructure, while everything else runs hosted because none of it has a residency requirement attached.

This is closer to how most teams actually land on it than the all-or-nothing framing implies. The decision isn't "self-hosted versus hosted" as a single switch, it's a per-component question, and the two hardest components to self-host well (mail and the audit anchor) are exactly the ones worth asking twice about before committing either way.

FAQ

Can you mix self-hosted and hosted Ujex components?

Yes. Because the core is Apache-2.0 and split into distinct components (Postbox, Approvals, Audit, Recall, Governor, Ingress), you can self-host the pieces that matter most for your compliance or cost situation and use the hosted version for the rest. A common pattern is self-hosting the mail server, since teams that already run deliverability infrastructure have a head start there, while using hosted audit anchoring so nobody has to build and babysit that job.

What's the single hardest piece of Ujex to self-host well?

The mail server behind Postbox. Getting DKIM, SPF, and DMARC configured correctly is doable in an afternoon. Keeping your sending reputation clean, watching DMARC aggregate reports, and staying off blocklists once your agents are sending real volume is ongoing work that doesn't stop once the initial setup is done.

If you start hosted, can you migrate to self-hosted later without losing your audit history's verifiability?

Yes. The audit-chain verifier itself is open source and separate from whichever mode produced the log. You can export your audit history and independently verify the hash chain regardless of whether it was generated by the hosted service or a self-hosted deployment, so switching modes later doesn't put you in a position of trusting a vendor's word for your own historical data.

Does self-hosting Ujex mean giving up the free tier?

Self-hosting and the free tier are separate axes. Self-hosting means running the Apache-2.0 core on your own Firebase project, which comes with its own Firebase costs (mostly Firestore reads and writes plus Cloud Functions invocations) rather than a Ujex bill. The hosted version has its own free tier for smaller usage before paid tiers apply.

Which option should a small team pick first?

If you don't have a data residency requirement yet, start hosted. It gets a working agent running fast enough to find out whether Ujex actually solves your problem before you spend engineering time on infrastructure. You can move to self-hosted later without rewriting your agent code or losing the ability to verify your audit history, so there's little cost to deferring the decision.