Before a microservice can do anything useful, it has to do the same dozen things every other service already does: read configuration, authenticate the caller, reach a database, cache a result, publish an event, fetch a secret, emit metrics and logs. Written once per service, that plumbing is duplicated, drifts apart, and ages badly.
Xeni's answer is Falcon — an in-house Go framework that every backend service is built on. Falcon owns the infrastructure so each service owns only its domain. It is the reason a small team can run many services without standing up a platform group behind each one.
This post is a tour of what Falcon does, how it is put together, and the tradeoffs we took on to build a shared foundation instead of many bespoke ones.
Falcon here is Xeni's own internal Go framework — not the unrelated open-source Python project of the same name. Everything below is Go.
The cost of not having one
Written once per service, that same infrastructure is duplicated and quietly drifts apart. Without a shared chassis, these costs recur in every service:
| Without a shared chassis | What happens |
|---|---|
| Repeated boilerplate | Every team re-implements routing, config, logging, auth, DB pools, cache, and metrics — weeks of work before the first business endpoint ships. |
| Inconsistent security | Services validate tokens, resolve tenants, and mask PII differently, and the gaps surface under audit and incident review. |
| Operational drift | Logs, metric labels, error envelopes, and correlation IDs differ by service, so debugging cross-service failures gets slow and fragile. |
| Vendor lock-in | Direct AWS or GCP SDK calls in product code make cloud or messaging migrations expensive and risky. |
| Slow onboarding | New engineers learn a different stack shape in every repo instead of one platform contract. |
| Scale friction | Connection pooling, distributed locks, retries, and eventing get reinvented — or skipped under delivery pressure. |
Falcon exists so product teams write domain logic, while the platform owns infrastructure correctness once — versioned, tested, and reused everywhere.
One chassis, every service
The platform is neither a monolith nor a scatter of unrelated apps. Every product vertical and every supporting service — supply, payments, identity, AI — is a separate service built on the same Falcon chassis. New products and new capabilities are additive: they inherit the foundation rather than rebuild it.
Interface Layer
Web
API
MCP
SDK
Product Verticals
Hotels
Flights
Cars
Activities
Resorts
Packages
Services
Supply & discovery
Supplier services
Aggregator services
Search & catalog
Auto Complete
Recommendations
Deals
Payments & settlement
FIAT payment service
Crypto payment service
Settlement service
Payment agents
Platform & AI
IDAM — identity & trust
AI backend service
Temporal jobs
Notifications
FALCON
shared Go chassis · config · auth · data · cache · streaming · secrets · observability
Data & streaming plane — Postgres · Redis · OpenSearch · Kafka
The same holds across the fleet. Beyond the products, the platform itself runs on Falcon — identity, configuration, accounts, reporting, operator tooling, payments, subscriptions, data migration, notifications, AI — and, for every vertical, aggregation services that unify dozens of provider-connector services. Every one of them is a Falcon service on the same chassis:
Services on Falcon
Identity (IDAM)
authN · authZ · trust
Config Management
central runtime config
Account Service
orgs · accounts · users
Reporting Service
analytics & reports
Customer Admin
Command Center console
Multi-Tenant Mgmt
Xeni operator tooling
Notification Service
email · SMS · push
AI Backend
agent & model serving
Payment Service
fiat & crypto · settlement
Data Migration
schema & data moves
Subscription Service
recurring plans & billing
Aggregation Services
tie dozens of connectors — each a service · per vertical
FALCON
shared Go chassis · config · auth · data · cache · streaming · secrets · observability
Data & streaming plane — Postgres · Redis · OpenSearch · Kafka
One call, and the plumbing is done
A new Falcon service starts with almost no infrastructure code. You create the server, register routes, and hand control to the framework:
// main.go — create the server, register the routes, hand off to the framework.
func main() {
falcon := server.NewFalcon()
routers.AddRouters(falcon)
falcon.Fly()
}
// routers.go — one line per endpoint:
// method, API version, path, allowed roles, request body, handler
func AddRouters(falcon *server.Falcon) {
falcon.Add(
routes.POST, routes.V2, "/bookings",
[]routes.Role{constants.ScopeAdmin},
&model.BookingRequest{}, handlers.Booking,
)
// ...more routes...
}Routes live in one routers.go — a single falcon.Add per endpoint, declaring the method, API version, path, the roles allowed to call it, the request body to bind and validate, and the handler. main.go does almost nothing: create the server, register the routes, and fly.
Every handler has the same signature — func(ctx) (interface{}, *APIError) — so the framework can centralize serialization, error-to-HTTP mapping, panic recovery, request-id and correlation propagation, and content negotiation. Everything a handler needs — configuration, database and cache clients, outbound clients — hangs off the request context, retrieved with server.Get*(ctx) helpers rather than passed around by hand. The handler itself doesn't do the work inline; it composes the request from small, independent workers — where the real domain logic lives.
From the product engineer's side, that makes a new feature a short, predictable checklist:
- 01Define the request model — Falcon binds and validates it from the body.
- 02Add one route line in
routers.go— method, version, path, roles, body, handler. - 03Write a thin handler that composes a workflow.
- 04Write the workers — small, independent units of domain logic (a validator, a policy, the steps).
- 05Wire any new dependency — a database, cache, or outbound service — through config, not code.
Everything else — authentication, authorization, structured logging, metrics, tracing, correlation IDs, error envelopes, serialization, panic recovery, and health / metrics endpoints — the framework already handles. That is the enablement: an engineer spends their time on the feature, not the plumbing.
Background work is just as light: falcon.AddBatch(name, fn) registers a startup job that runs in its own goroutine — the same wiring, without an HTTP route.
Config is the wiring
Falcon is configuration-driven. Nearly every capability — a database, a cache, an outbound HTTP client, a stream, a cloud provider — is instantiated from a named config group with a declared type. Adding a downstream dependency is a configuration change, not new code.
Configuration is a flat, dotted-key format — <service>.<group>.<key>=<value> — loaded either from a local file or from a central config service (authenticated with a service-to-service token). Falcon discovers groups by that middle segment, which is how a single service can wire several typed databases (for example separate tenantdb and coredb groups), multiple streams, or many outbound clients purely through config. Typed getters return values with sane defaults, so the same binary behaves correctly across every environment — and operators can even change log verbosity at runtime with PUT /loglevel/:level, no restart required.
Batteries included
Falcon ships the infrastructure a production service needs, each piece behind a clean interface:
| Area | What Falcon provides |
|---|---|
| API & middleware | Gin-based versioned routing (v1–v4), request-id / correlation, timeouts, panic recovery, CORS, health / pprof, and a metrics endpoint |
| Data | GORM over Postgres, MySQL, and CockroachDB; OpenSearch (with reindex support) for search and catalog |
| Cache | Redis with distributed locking, plus AWS DAX |
| Messaging | A unified streaming layer — Kafka for publish and consume, with Kinesis and Google Pub/Sub on the publish side |
| Workflows | An in-house request-pipeline engine, plus Temporal for durable, long-running work |
| Transports | HTTP for service-to-service calls, with connection pooling and retry-with-backoff; with gRPC and the AI-agent transports (SSE, MCP, agent-to-agent) on the roadmap |
| Cloud | One interface over AWS and GCP for storage, secrets, and KMS |
| Security | AES-GCM encryption and Ed25519 signatures (with Base32/64/Hex/Ascii85 codecs), multi-strategy authorization, service-to-service auth, and PII masking |
| Observability | Structured logging (zap, with optional Loki shipping), Prometheus metrics, and audit events |
| Concurrency | Goroutine pooling with backpressure |
None of this is novel on its own — the value is that it is uniform. Every service reaches a database, emits a metric, or signs a payload the same way, so an engineer who has worked in one Falcon service is immediately productive in the next.
It is also opt-in: each capability is switched on per service in configuration (falcon.<feature>.enabled=true), so a lean service carries only what it actually uses and pays nothing for the rest.
How a request flows
End to end, every request moves through the same ordered stages, so behavior is predictable no matter which service handles it:
- 01Ingress. The middleware chain stamps a request and correlation ID and applies timeout, metrics, and CORS.
- 02Authenticate. The caller's token is validated — an OAuth Bearer token checked against a central auth service, or a locally-verified JWT — and its scopes are extracted.
- 03Authorize. A multi-strategy check resolves the caller's identity and permissions, with per-tenant policy lookups cached in Redis — Xeni is consolidating these strategies onto IDAM.
- 04Assemble context. The request-scoped
contextis enriched with config, database and cache clients, outbound clients, tenant and user identity, and correlation IDs. - 05Handle. The product handler runs — typically by composing the workflow pipeline below.
- 06Respond. Output is content-negotiated — JSON by default, HTML and PDF for human-facing documents, and raw bytes for files — with automatic error-envelope formatting. Streaming responses (SSE, NDJSON) are on the roadmap; XML remains available for legacy consumers.
- 07Audit. Request and workflow events, with sensitive fields masked, are published to the notification stream.
Every request runs the same shape
Falcon services handle requests as an explicit pipeline rather than a tangle of handler code:
A handler composes that pipeline as a fluent chain — Falcon's workflow engine:
resp, err := workflow.NewWorkflowEngine("Booking").
AddValidator(ctx, &InputValidator{}).
AddPolicy(ctx, &FraudPolicy{}).
AddWorker(ctx, &Booking{}, false).
AddWorker(ctx, &Payment{}, false).
AddErrorHandler(ctx, &ErrorHandler{}).
Execute(ctx)Its real power is that workers are independent units of work. Each implements a small interface — IsEligible, Skip, and Execute — and the same worker can be composed into different workflows to solve different business needs. A Payment worker written once is reused across a booking, a refund, and a subscription renewal; a validator or fraud policy drops into any flow that needs it.
The engine chains the workers' outputs, tracks per-task status in a WorkFlowStatus, emits a workflow event at every step, and routes any failure to the registered ErrorHandler — giving every service consistent handler structure and observable, testable, composable business logic.
It is the same pattern behind Xeni's identity service: a new capability is a matter of writing a worker and wiring one route.
Swap the vendor, not the code
Because the backing technologies sit behind interfaces, they can change without touching product code. The cloud provider (AWS or GCP), the cache (Redis or DAX), and the streaming backbone (Kafka, Kinesis, or Pub/Sub) are all selected by configuration and resolved through a factory. A vendor swap happens inside the framework.
The strategic effect compounds: a new service starts with zero infrastructure code, and the marginal cost of the next service — and the next supplier, market, or product — keeps falling as the framework absorbs more of the common work.
One pattern, cross-owned services
Common plumbing is only half of what Falcon buys. The other half is discipline: because the framework fixes the shape of a service — one handler contract, one request pipeline, one way to reach each dependency, one error and logging model — every service ends up looking like every other service.
That uniformity changes how the team works. Engineers are not siloed to the service they happened to build; anyone who knows one Falcon service can read, extend, and debug the next. Services are cross-owned rather than guarded — which spreads knowledge, removes single points of failure in the team, and shortens onboarding to days.
It matters most when something breaks. The same logs, the same metrics, and the same pipeline stages in every service mean whoever is on call can orient inside an unfamiliar service and fix it quickly — live troubleshooting doesn't wait for the one person who wrote it. Shared plumbing plus enforced patterns turn "who owns this?" into "any of us can."
The outcome is leverage: a small team builds and operates a broad platform, and the ratio of services to engineers keeps improving as the framework absorbs more of the common work.
The tradeoffs we take on
A shared foundation is a deliberate bet, and it is not free:
- Concentrated risk. A bug in Falcon can reach every service at once. That raises the bar: the framework carries a higher standard of review, testing, and careful versioning than any single service does.
- It asks for depth. Falcon needs real Go expertise and a team that treats the framework as a product with its own roadmap — not a side project.
- It has to stay ahead. The framework must anticipate what product teams will need next; when it lags, every team feels the drag.
We take these on because the alternative is worse. Letting every team re-solve configuration, auth, data access, and observability produces slower delivery, inconsistent behavior, and a security posture that is impossible to reason about uniformly. Centralizing the hard parts is what lets the rest move fast.
Why it holds up
- 01Isolate infrastructure from product. A service should contain domain logic and little else.
- 02Make every service look the same. One handler contract, one request pipeline, one way to reach each dependency.
- 03Put topology in configuration. Adding a database or a downstream client is a config change, not a rewrite.
- 04Hide vendors behind ports. Cloud, cache, and streaming can change without product code noticing.
- 05Own the framework as a product. Accept the concentrated risk, and pay it down with review, tests, and versioning.
Strategic value at a glance
Stepping back from the mechanics, the business payoff is straightforward:
| Business goal | How Falcon delivers |
|---|---|
| Faster product delivery | New services start with zero infrastructure code — teams focus on domain logic. |
| Consistency across services | Auth, logging, metrics, events, and error handling behave identically everywhere. |
| Vendor & tech-stack agility | Cloud, streaming, cache, and web-layer concerns are abstracted behind Falcon. |
| Horizontal scale | Stateless services, connection pooling, distributed locking, and stream decoupling. |
| Security & compliance | Centralized auth, PII masking, and KMS-backed cryptography enforced uniformly. |
| Operational maturity | Prometheus metrics, structured logs, health and pprof endpoints, and audit events out of the box. |
Closing
Falcon is easy to underestimate because, when it works, you don't see it: services just start with the plumbing already handled. But it is the quiet reason Xeni can run a broad platform — identity, payments, search, and the product verticals — on a common chassis instead of a pile of one-offs.
Put plainly, Falcon is the connective tissue of the platform: it turns what would otherwise be dozens of independent infrastructure decisions per service into a single, versioned, config-driven contract. That is why we treat it as a first-class internal product — with dedicated maintainers, a stable release cadence, and a clear deprecation policy for legacy paths — not a shared utility no one owns.
The framework is the leverage: solve infrastructure once, and inherit it everywhere. The clearest example of a service built entirely on that leverage is Xeni's identity layer — the subject of the companion post, Inside IDAM.
Written for the Xeni Engineering blog. Describes the Falcon framework as of July 2026. Code sample is illustrative of the framework's API shape.