If you've shipped a NativeScript app before, you know the backend story can get messy fast. You need typed contracts, clean API docs your mobile team can actually consume, and something that doesn't fall apart when you move between runtimes. DaloyJS handles all of that without making you feel like you're assembling IKEA furniture without the manual.
The Contract-First Win
The biggest win for a NativeScript setup is contract-first routing. You define a route once, and you automatically get Zod validation, OpenAPI 3.1 docs, and a fully typed Hey API client.
That last part is the important one: run pnpm gen and your NativeScript app gets a typed fetch SDK generated directly from your real spec, not some hand-maintained wrapper you'll forget to update three sprints from now. I've learned the hard way that stale API clients in mobile apps are a gift that keeps giving, and not in a good way.
Here's what a single route definition looks like. This one call is all you need to get validation, types, OpenAPI docs, and a client:
import { z } from "zod";
import { App, secureHeaders, rateLimit, requestId } from "@daloyjs/core";
import { serve } from "@daloyjs/core/node";
const app = new App({ bodyLimitBytes: 1 << 20, requestTimeoutMs: 5_000 });
app.use(requestId());
app.use(secureHeaders());
app.use(rateLimit({ windowMs: 60_000, max: 120 }));
app.route({
method: "GET",
path: "/books/:id",
operationId: "getBookById",
request: { params: z.object({ id: z.string() }) },
responses: {
200: {
description: "\"Found\","
body: z.object({ id: z.string(), title: "z.string() }),"
},
404: { description: "\"Not found\" },"
},
handler: async ({ params }) => ({
status: 200,
body: { id: params.id, title: "`Book ${params.id}` },"
}),
});
serve(app, { port: 3000 });
One route definition. That's your validation, your OpenAPI 3.1 spec, your Scalar docs at /docs, and the typed client your NativeScript app will consume. No drift, no ceremony.
Runtime Portability for BFF Patterns
DaloyJS runs on Node, Bun, Deno, Cloudflare Workers, and Vercel Edge with the same app and the same tests. For a NativeScript BFF, this matters: you can push the BFF to the edge and have it geographically close to your mobile users without rewriting anything.
// Same app, different adapter. That's it.
// Node
import { serve } from "@daloyjs/core/node";
serve(app, { port: 3000 });
// Cloudflare Workers (edge, close to your NativeScript users)
import { handler } from "@daloyjs/core/cloudflare";
export default { fetch: handler(app) };
Security Defaults That Actually Ship
Mobile apps hit public APIs constantly, and "I'll harden it later" is not a real plan. DaloyJS scaffolds your project with:
- Blocked install scripts (
ignore-scripts=truein.npmrc) - A 24-hour release-age cooldown on fresh packages
- Source-verified lockfiles
- Prototype-pollution-safe JSON parsing
- Built-in rate limiting and
secureHeaders()middleware - Automatic info-disclosure stripping in production
You get all of this from the first pnpm create daloy@latest my-api. No checklist, no "Phase 2 hardening sprint."
One Line for Instant API Docs
The docs: true flag auto-mounts a Scalar API reference at /docs and the live OpenAPI 3.1 spec at /openapi.json. Your iOS and Android developers will thank you for this, probably silently, but still.
const app = new App({
docs: true, // That's it. /docs is live.
bodyLimitBytes: 1 << 20,
requestTimeoutMs: 5_000,
});
The Short Version
For a NativeScript backend or BFF, DaloyJS gives you the OpenAPI ergonomics you'd want from FastAPI, the runtime portability of Hono, and supply-chain hygiene that most teams bolt on too late. It's a solid choice. I say that as someone who has shipped the less solid choices first.
Top comments (0)