Skip to main content
One supported production shape puts the Next.js frontend on Vercel and the Pylon backend on Pylon Cloud (Fly Machines internally). This guide takes you from a scaffolded Next.js and Pylon monorepo to a live production URL. If you do not need a separate Next.js app, Pylon’s default scaffold serves server-rendered React and the API from one port (see Deploy), and you can skip Vercel entirely. If you have not scaffolded yet, generate the Next.js and Pylon monorepo:
That gives you apps/api (Pylon backend) and apps/web (Next.js frontend), ready to deploy. apps/web/next.config.js already proxies /api/* to the backend on :4321.

1. Deploy the backend to Pylon Cloud

Sign in at www.pylonsync.com, create an organization, and connect the GitHub repo. The setup wizard provisions a Fly Machine, points it at apps/api/app.ts, and gives you a default hostname:
Push to the branch you configured (default: main), and Pylon Cloud deploys it automatically. You can also add a custom domain (api.example.com) in the project’s Domains tab. We recommend this once you go live, because it keeps the URL stable across project renames.

2. Deploy the frontend to Vercel

Create a Vercel project pointed at the same GitHub repo. In Project Settings → Build & Development Settings:
  • Framework Preset: Next.js (auto-detected)
  • Root Directory: apps/web
  • Install Command: bun install (or your package manager)
  • Build Command: next build
Vercel picks up apps/web/next.config.js automatically.

3. Set the backend URL

In Project Settings → Environment Variables, add: The Next.js template’s next.config.js rewrites /api/* to ${PYLON_TARGET}/api/*, so the browser always talks same-origin to Vercel, and Vercel forwards the request to your Pylon backend. This is the recommended pattern: it avoids CORS preflight requests and lets the session cookie work without cross-site cookie settings. For local dev (bun run dev), PYLON_TARGET defaults to http://localhost:4321 so no .env.local is required when your backend is pylon dev on the same machine.
If you would rather skip the rewrite and have the browser talk to your Pylon backend directly, set Domain=.example.com on the session cookie, and set allowed-origins in your Pylon manifest to your Vercel hostname. See the cookie checklist below.

4. Configure CORS (only if you skipped the rewrite)

If your Next.js rewrite proxies /api/*, you do not need CORS. The browser only sees the Vercel origin. If your frontend talks to Pylon Cloud directly (fetch("https://api.example.com/api/fn/...") from the browser), open your project’s Settings → CORS tab on Pylon Cloud and add your Vercel deployment URLs:
Vercel mints a unique preview URL per deployment, so use the wildcard pattern for the preview environment.

5. Push and verify

  • Vercel build: takes about 30 seconds. Watch the deploy log for the build step.
  • Pylon Cloud deploy: runs in parallel. Check the project’s Deployments tab.
Once both finish, open your Vercel URL. You should see your app, and the Network tab should show /api/* requests succeeding (status 200, Set-Cookie header on auth endpoints). If session cookies are not sticking, work through this list:
  • Cookie name matches. Pylon emits ${app_name}_session. Your createPylonServer({ cookieName }) and createPylonProxy({ cookieName }) must pass the same name. A mismatch causes silent 401 errors.
  • Same-site defaults to Lax. Pylon defaults to SameSite=Lax, which works with Next.js’s same-origin pattern. If you must use cross-site cookies (skipping the rewrite), set PYLON_COOKIE_SAME_SITE=None and PYLON_COOKIE_SECURE=true.
  • Domain matches. If the frontend is app.example.com and the backend is api.example.com, set PYLON_COOKIE_DOMAIN=.example.com so the cookie applies to both subdomains. Do not set this if you are using the rewrite pattern; host-only cookies are tighter.
  • iOS Chrome and Safari. iOS browsers reject domain-scoped cookies when a host-only cookie of the same name is present. Pylon v0.3.140+ handles this by pairing every domain-scoped set with a host-only Max-Age=0 clear. Make sure your Pylon backend is on a recent framework version.

Custom domain end-to-end

With this layout you set:
  • Pylon Cloud project domains: api.example.com
  • Vercel project domains: app.example.com
  • Vercel env var: PYLON_TARGET=https://api.example.com
  • Your next.config.js rewrite continues to forward /api/* to ${PYLON_TARGET}/api/*
No CORS configuration is needed. The browser only ever talks to app.example.com.

Troubleshooting

Build fails: “Module not found: @pylonsync/next”. You are probably building from the repo root instead of apps/web. Set Vercel’s Root Directory to apps/web. Too many requests. Limit: 100 per 60s from the dashboard. Pylon defaults to 100 requests/min per authenticated user. Raise it with PYLON_RATE_LIMIT_MAX_AUTHED (default 1000 since v0.3.148) on your Pylon Cloud project. PYLON_BACKEND_UNREACHABLE errors in Next.js logs. Your Pylon Cloud machine is stopped (autostop after idle) or restarting. The server helpers time out after 5s, and an error.tsx boundary makes this graceful. Restart the machine from the project’s Overview tab. Live queries do not update across tabs. The sync engine WebSocket may be misrouted. Check that PYLON_TARGET resolves, and that your browser’s WebSocket connection (DevTools → Network → WS) connects to wss://<your-target>/api/sync successfully.

Next steps

Custom domains

Wire DNS for your Pylon Cloud project.

Cookie & sessions

Full cookie config reference.

Next.js SDK

All @pylonsync/next APIs.

Pylon Cloud

Project management, scaling, custom domains.