If you're building a cross-platform mobile app with Lynx, you already made a smart call. Write once in React-style components, get native rendering on iOS and Android. Clean. But now you need a backend, or more specifically, a BFF (Backend for Frontend), and that choice matters more than most people think.
I've shipped backends in Express, Fastify, and a few others I'd rather not name. Here's why I'd pick DaloyJS for a Lynx project today.
One Contract, No Surprises
The biggest headache in mobile development is API drift: the backend changes a response shape, the app breaks, and nobody catches it until a user screenshots a crash. DaloyJS solves this at the source. You define the route once, and validation, OpenAPI 3.1 docs, and a typed client all come from that same definition. Nothing to keep in sync.
import { z } from "zod";
import { App, requestId, secureHeaders, rateLimit } from "@daloyjs/core";
import { serve } from "@daloyjs/core/node";
const app = new App({
bodyLimitBytes: 64 * 1024,
requestTimeoutMs: 5_000,
openapi: { info: { title: "Lynx App API", version: "1.0.0" } },
docs: true,
});
app.use(requestId());
app.use(secureHeaders());
app.use(rateLimit({ windowMs: 60_000, max: 120 }));
app.route({
method: "GET",
path: "/feed/:userId",
operationId: "getUserFeed",
tags: ["Feed"],
request: { params: z.object({ userId: z.string().uuid() }) },
responses: {
200: {
description: "User feed",
body: z.object({
items: z.array(z.object({ id: z.string(), title: z.string() })),
}),
},
404: { description: "User not found" },
},
handler: async ({ params }) => ({
status: 200,
body: { items: [{ id: "1", title: `Feed for ${params.userId}` }] },
}),
});
serve(app, { port: 3000 });
That's it. Hit http://localhost:3000/docs and you have a live Scalar API reference. Your Lynx app gets a typed SDK with pnpm gen. No manual swagger files. No stale docs.
Built for the BFF Role
DaloyJS explicitly calls out BFF as one of its sweet spots, and the kit it ships proves it. fetchGuard() blocks SSRF and private network calls by default. Session management with signed cookies is first-party. Rate limiting works out of the box. These are exactly the concerns a BFF sitting between your Lynx app and your internal services has to handle, and here they're already handled.
Deploy Anywhere, Stay Consistent
Lynx targets iOS and Android. Your backend has to be reliable and fast. DaloyJS runs on Node, Bun, Deno, Cloudflare Workers, Vercel Edge, and AWS Lambda, same app code, different adapter. I've personally appreciated this when a project's infrastructure changed mid-flight. (It happens more than anyone admits in retrospect.)
Security Without the Ceremony
Most frameworks treat security as optional configuration you add later and then forget. DaloyJS ships with prototype-pollution-safe JSON, automatic 5xx info-disclosure stripping in production, and a hardened pnpm scaffold with ignore-scripts=true and a 24-hour release-age cooldown. For a mobile app touching real user data, this isn't optional, it's the baseline.
The Bottom Line
Lynx gives your mobile app native performance with web-friendly code. DaloyJS gives your backend contract-first discipline, typed clients, edge-ready deployment, and security defaults that don't require a second pass. The two pair naturally. Scaffold with pnpm create daloy@latest my-lynx-api, wire up your Lynx frontend to the generated typed client, and you have a stack worth shipping.
DaloyJS is MIT licensed. The name means "flow" in Tagalog. Fitting, given how little glue code you end up writing.