Embed & one process
Mount your frontend inside the CMS — one port, one URL, WordPress-style.
site: in cms.config.js names a module the CMS mounts at /. The CMS claims /api, /studio and /uploads first; everything else goes to your module — same process, same port. CommonJS and ESM both load, and a wrong export fails at boot naming the file and both valid shapes.
The contract — detected by shape
Next.js on one port
Point site: "./web/site.js" at it and prelo dev serves your Next pages at /, the studio at /studio and the API at /api — one port, one deploy. Your server code fetches content from the same port (http://localhost:3300/api/post). For Astro, build with @astrojs/node in middleware mode and export the built handler; an Express app is itself a valid handler. npx create-prelo my-site --framework scaffolds this shape.
The render module (starter shape)
GET-only. ctx carries cmsUrl (the local API base) and headers (the visitor's cookie, when present) — pass ctx.headers on every API fetch.
Draft preview
The content API serves drafts to author-and-above credentials only. In one-process mode the visitor's cookie reaches the site module, so anyone signed into the studio sees drafts on the real site — the starter renderer marks them with a "draft" pill. With your own framework, forward req.headers.cookie on CMS fetches for the same behavior. Shareable tokenized preview links don't exist yet.
The programmatic API
When to go fully headless instead
Keep one process unless the frontend must live on other infrastructure — Vercel, a static CDN, an existing deployment. Then omit site:, point the frontend at the CMS URL, and set webhooks: { onPublish: "https://…/api/revalidate" } — every publish POSTs { event: "publish", type, slug, id } so the frontend revalidates. Drafts and private types are fetched server-side with a key. See Deploy.