← All news

The engineering principles behind Seldeo

The team shape

Seldeo is built by a small team. Every architectural decision on the app is downstream of that fact. We do not have the luxury of standing up a separate team per platform. We cannot afford three different infrastructure vendors for three services that should be one. We cannot spend a quarter solving a problem we could have avoided by picking a different tool up front.

Almost every engineering question at Seldeo therefore comes down to the same trade-off: what lets a small team ship a big product without cutting corners on the things that matter? The principles below are how we answer that.

Principle 1: One codebase, two platforms

Seldeo's mobile app ships to iOS and Android from a single codebase. Every pixel of the UI is rendered by our own code, not by the platform's native widget system. This means a small team can ship a feature once and have it work identically on both platforms without a per-platform team.

The trade-off is honest: a native-per-platform stack would give us more UI polish in a few niche places, and would let us hit some platform-specific APIs faster. For the product we're building — a social app where feature parity and shipping speed matter more than the last five percent of platform-native feel — the trade is worth it.

Principle 2: Managed infrastructure for the boring parts

Boring infrastructure is boring on purpose. Authentication, databases, file storage, push delivery, real-time media routing — these are commodity capabilities that a small team should not be reinventing. Where a mature managed provider does a good job at a fair price, we use one.

Our infrastructure choices are made with three questions in mind:

  1. Does this vendor let a small team stand up a capability in days, not months?
  2. Can we walk away from this vendor without rewriting the app? For every piece of managed infrastructure we adopt, we prefer the ones that expose standard interfaces we could migrate to a different provider.
  3. Does the vendor's compliance posture match ours? Regulated regions (EEA, UK, Brazil, California) impose real requirements on where data can be processed and under what contracts. A vendor whose compliance story is thin becomes our problem, not theirs.

The specific vendors we use are enumerated in our Privacy Policy under the "Sharing" section. That page is the authoritative list. This page is about the engineering philosophy that led us to pick them.

Principle 3: Own the security boundaries yourself

Some things a small team should not outsource. Chief among them: the security boundaries. Every design decision that sits on our security perimeter — end-to-end message encryption, per-user data isolation, credential handling, rate limits, App Check on every server-side callable — is built and reviewed by us, not delegated to a vendor's default.

The rule of thumb: a vendor can carry the transport, but never the trust decision. Real-time media routing can be outsourced; the encryption of the media stream stays ours. Database hosting can be outsourced; the rules that decide who can read what row stay ours (see the E2EE messaging post and Recovery, step-up, and passkeys for concrete examples).

Principle 4: Kill switches, always

Every feature that touches an external network — ads, push notifications, translation, third-party media — has a runtime kill switch. Configuration for the kill switches lives in a remote-config layer that we can flip in seconds without shipping a new app build.

We use this a handful of times a year: to shut off a feature when a downstream service degrades, to roll a new capability out incrementally, to react to a compliance event without waiting for an app store review cycle. The overhead of building the kill switch upfront is low. The value of having it available on the day something goes wrong is enormous.

Principle 5: Feature flags aren't experiments

Some teams run their product on A/B tests. Every user is in a bucket, every feature is a live experiment, every decision is decided by the number that comes out.

We don't. Feature flags exist at Seldeo — they're the same mechanism as the kill switches described above — but their purpose is different. A flag lets us roll a new feature out to internal accounts, then friends-and-family, then five percent of new users, then everyone. It's a safety mechanism, not a decision-making one.

The reason: our feed ranker target is not engagement. A/B testing for engagement is a very effective way to accidentally build the loudest product; we would rather deliberate over changes and be occasionally wrong than optimise our way into a different company.

Principle 6: Static, prerendered, no cross-site scripts

The corporate website — the one you're reading — is statically prerendered on every deploy. Every page is served as HTML that was generated at build time, not computed at request time. Every asset it loads comes from our own domain. There is no tracking script, no analytics tag, no third-party font, no ad slot on this site.

This gives us three things: a page that loads fast on every network, a page that respects a reader's browser default without a per-vendor negotiation, and a page that has a much smaller attack surface than a site full of third-party embeds.

Principle 7: Content is code

Every article on this news feed, every help-center page, every legal page, and every static page is a Markdown file in a Git repository. The site is generated from those Markdown files at build time. Version control is our content management system.

The advantages:

  • Diffs are reviewable. A change to the help center goes through the same code review as a change to the app.
  • Rollbacks are trivial. Reverting a bad content change is a git revert, not a CMS restore.
  • Deployments are atomic. The whole site ships together, so a copy change and a UI change land in sync.

For a team our size, this beats every hosted CMS on the market.

Principle 8: No premature scale

We are aggressive about not solving problems we do not have. We do not shard databases we do not need to shard. We do not build multi-region failover for features that have not yet had a single regional outage. We do not introduce a caching layer for read paths that have not yet been measured as slow.

The rule of thumb: solve the problem you can measure, not the problem you can imagine. Almost every "we might need this at scale" decision we've deferred has stayed deferred. Almost every "we might need this at scale" decision we've taken has turned out to be a distraction from something more important.

Principle 9: Publish the receipts

For anything user-facing that is easy to hide behind opacity — the ranker (see A quieter feed), the safety model (see The trust and safety model behind Seldeo), notification policy (see Notifications, restrained) — we publish the specifics in advance. This is a deliberate discipline: publishing forces us to keep the implementation aligned with the promise.

If any of the specifics on this site ever drift from the actual behaviour of the app, someone will notice — either inside the team or outside — and we'll be embarrassed into fixing the drift.

What we don't do

  • We don't use A/B testing as a decision-making tool — see Principle 5.
  • We don't run behavioural nudges — no engagement streaks, no "your friend just posted, go react?"
  • We don't have a CMS. Content is Markdown in a repo.
  • We don't have a tracking analytics vendor on the mobile app. The analytics we need are computed in our own backend, scoped to what the product actually requires, and disclosed in the Privacy Policy.
  • We don't have a CDN in front of our hosting, because our hosting is CDN-fronted by default and we haven't needed a second layer.

Contributing back

Where we depend on open-source software, we upstream the patches we write. Where we build something generally useful that isn't tied to Seldeo's specific domain, we look for the chance to publish it as an open-source package under our organisation. Our third-party attribution list is at /open-source-licenses.

If you're an open-source maintainer whose project we depend on and something we do is causing you pain (an issue we should have reported, a bug we should have patched, a use case we should describe), please email oss@seldeo.com. We answer that mailbox.