Anyone using Zoho Catalyst as a backend for a modern web application quickly faces a challenge: How do I develop locally when Catalyst provides OAuth, SDK initialization and serverless functions via its own endpoints? In this post, I show how I set up local development of my Nuxt app with Zoho Catalyst productively and stably.
The problem: Two servers, one browser
In production, everything runs through Catalyst: The Nuxt app is deployed as a static SPA, Catalyst takes care of authentication, SDK initialization and the execution of serverless functions. Locally, the world looks different:
- Nuxt Dev Server runs on
localhost:3000and serves the app with Hot Module Replacement. - Catalyst CLI (
catalyst serve) runs onlocalhost:3838and provides OAuth, the SDK and local authentication.
The problem: The browser only talks to localhost:3000. Requests to Catalyst endpoints like /__catalyst/sdk/init.js or /oauthorize go nowhere because Nuxt doesn't know about them.
The solution: Vite Proxy as a bridge
Nuxt uses Vite as its dev server under the hood. Vite comes with a built-in proxy function that can transparently forward requests to other servers. That's exactly what I took advantage of.
In my nuxt.config.ts, I forward all relevant Catalyst routes via Vite Proxy to the right place:
vite: {
server: {
proxy: {
"/__catalyst": {
target: "http://localhost:3838",
changeOrigin: true,
},
"/accounts": {
target: "http://localhost:3838",
changeOrigin: true,
},
"/oauthorize": {
target: "http://localhost:3838",
changeOrigin: true,
},
"/server": {
target: "https://my-app.development.catalystserverless.eu",
changeOrigin: true,
secure: true,
},
},
},
},What exactly happens here?
/__catalyst– The Catalyst SDK is initialized via this path. Without the proxy, the script wouldn't load in the browser./accountsand/oauthorize– These routes are needed for the OAuth login flow. Catalyst uses them to direct users to login and back./server– Calls to my serverless functions. Here I point the proxy not to the local Catalyst server but to the deployed version in the cloud. There's a good reason for this: The functions always run stably against the current server version, regardless of whether I'm currently working on the function logic or not.
Starting both servers in parallel
So I don't have to open two terminals every time, I set up a script in package.json that starts both processes simultaneously:
{
"scripts": {
"dev": "concurrently \"catalyst serve\" \"nuxt dev\""
}
}With a single npm run dev, Catalyst CLI and Nuxt Dev Server run in parallel. The proxy ensures everything is accessible via localhost:3000.
Important: Only active in dev mode
One point that was important to me: The proxy configuration under vite.server.proxy only applies in development mode. During the production build (nuxt generate or nuxt build) it's completely ignored. So there's no risk of local proxy rules accidentally making it into production.
Integrating the Catalyst SDK
To make the Catalyst SDK available in the browser, I include two scripts in the app.head section of my Nuxt config:
script: [
{
src: "https://static.zohocdn.com/catalyst/sdk/js/4.3.0/catalystWebSDK.js",
type: "text/javascript",
},
{
src: "/__catalyst/sdk/init.js",
type: "text/javascript",
},
],The first script loads the SDK from Zoho's CDN. The second (/__catalyst/sdk/init.js) is forwarded to the local Catalyst instance via the proxy and configures the SDK with the correct project credentials.
Testing OAuth login locally
The OAuth flow was the trickiest part. Catalyst expects users to be redirected to a specific URL after login. Locally, this means: The redirect must point to localhost:3000, not the Catalyst domain.
My solution: A custom redirect page that only exists locally and receives the auth token to forward it to the actual app.
Conclusion
The combination of Nuxt and Zoho Catalyst works great locally when you use the Vite Proxy correctly. The core idea is simple: Everything related to Catalyst is routed to the right place via the proxy – auth routes to the local Catalyst server, function calls to the deployed version in the cloud.
The setup requires some initial configuration but then runs stably and requires no further adjustments. Developers can work with full hot reload while authentication and backend calls work normally.