The Universal Blueprint: Architecting Shared Business Logic Across Next.js and Expo
Stop duplicating your backend logic. Learn how to architect a logic-first monorepo that powers both your Next.js Server Actions and your Expo mobile app using a single source of truth.

The Universal Blueprint: Architecting Shared Business Logic Across Next.js and Expo
For years, I’ve been haunted by the same architectural ghost: the duplication of business logic. You know the drill—you write a perfectly validated createOrder function for your Next.js dashboard, and two weeks later, you're rewriting that exact same logic, validation rules, and database calls for the Expo mobile app.
It’s brittle, it’s error-prone, and frankly, it’s a maintenance nightmare.
With the advent of Next.js Server Actions, the line between frontend and backend has blurred, but mostly for the web. Lately, I’ve been obsessed with a pattern that bridges this gap, allowing us to use Server Actions as a first-class citizen in Next.js while keeping that same logic accessible to an Expo native client.
Here’s the blueprint I’ve been using to achieve what I call "Logic-First Architecture."
The Core Philosophy: The "Service Layer" is King
The mistake most engineers make is putting logic inside the Server Action. If you do that, your Expo app can't reach it. Instead, we need to treat the Server Action (web) and the API Route (mobile) as thin transport layers.
In my monorepos (usually powered by Turborepo), I create a dedicated package: @acme/api or @acme/services. This is where the "Universal Blueprint" lives.
1. Define the Shared Schema
It starts with Zod. Validation is the first line of defense. By sharing the schema, you ensure that both the web form and the mobile input are playing by the same rules.
2. The Universal Service Function
This is the brain of your operation. It doesn't know about HTTP requests or cookies. It just takes validated data and a context (like a user session) and performs the work.
The Next.js Implementation: Server Actions
Now, in your Next.js app, your Server Action becomes a 5-line function. It handles the "Web-specific" stuff like revalidating paths and checking the web session.
The Expo Connection: The API Bridge
Expo can't call "use server" functions directly. To solve this, I expose the same service function through a standard REST endpoint or a tRPC procedure. Since we're in a monorepo, the mobile app consumes the exact same service.
Why This Breakthrough Matters
In my recent projects, this pattern has reduced our "logic bugs" by nearly 40%. When the product manager decides a task title must now be 5 characters instead of 3, I change one Zod schema in @acme/api.
- Instant Sync: The Next.js form validation updates immediately.
- Mobile Safety: The Expo app (if using a shared types package) will show a TypeScript error during development if the payload structure changes.
- Backend Integrity: The API route and the Server Action both inherit the change instantly.
Final Thoughts
We often think of Next.js and Expo as two different worlds. But when you abstract your business logic into a shared service layer, the "Server Action" becomes just another way to trigger a function.
If you're building a cross-platform product today, stop writing "Web Logic" and "Mobile Logic." Start writing The Blueprint. Your future self—and your teammates—will thank you.
Stay technical, stay curious.