Deployment (Cloudflare Pages)
Every app is a static build. A GitHub Actions workflow builds the monorepo and deploys each app to its own Cloudflare Pages project with wrangler. The workflow runs on every push to main and on every pull request, so each PR gets its own preview URL.
Domain and subdomains
Section titled “Domain and subdomains”All web surfaces live under esimm.app, one subdomain per project.
| Subdomain | Cloudflare project | What it serves |
|---|---|---|
newsstand.esimm.app | mars-newsstand | Community Newsstand app |
miam.esimm.app | mars-miam | Mars in a Moment app |
docs.esimm.app | mars-docs | This documentation site |
design.esimm.app | mars-design | Design system (Ladle) |
innovation.esimm.app | mars-innovation | Innovation app (not built yet) |
install.esimm.app | mars-install | Installer download page (not built yet) |
The last two projects are added when those apps exist.
How the workflow works
Section titled “How the workflow works”The workflow is .github/workflows/deploy.yml.
- Typecheck runs once for the whole monorepo. If it fails, nothing deploys.
- Deploy runs as a matrix, one leg per app. Each leg installs dependencies, builds just that app, and deploys its
distfolder to the matching Cloudflare Pages project. - On a pull request, each leg posts the preview URL as a comment on the PR.
To add a new app later, add one entry to the matrix include list in the workflow. Nothing else changes.
One-time setup
Section titled “One-time setup”1. Domain
Section titled “1. Domain”Register esimm.app in the Cloudflare dashboard (Registrar) and let Cloudflare manage its DNS.
2. Cloudflare API token
Section titled “2. Cloudflare API token”In the Cloudflare dashboard, go to My Profile then API Tokens then Create Token. Use the Edit Cloudflare Workers template, or a custom token with the Cloudflare Pages: Edit permission. Copy the token.
Also copy the Account ID from the dashboard sidebar.
3. GitHub secrets
Section titled “3. GitHub secrets”In the GitHub repo, go to Settings then Secrets and variables then Actions, and add:
CLOUDFLARE_API_TOKEN— the token from step 2CLOUDFLARE_ACCOUNT_ID— the account ID from step 2
4. Create the Pages projects
Section titled “4. Create the Pages projects”Each app needs a Pages project of type Direct Upload (not Git connected, because the workflow uploads the build). Create one per app.
From the dashboard: Workers & Pages then Create application then Pages then Upload assets. Name the project (for example mars-miam) and set its production branch to main.
Or from the command line:
npx wrangler pages project create mars-newsstand --production-branch=mainnpx wrangler pages project create mars-miam --production-branch=mainnpx wrangler pages project create mars-docs --production-branch=mainnpx wrangler pages project create mars-design --production-branch=main5. Custom domains
Section titled “5. Custom domains”In each project, open the Custom domains tab and add the subdomain from the table above (for example miam.esimm.app). Cloudflare creates the DNS record automatically because it manages the esimm.app zone.
- Production (push to
main):https://<subdomain>.esimm.app - Default Pages URL:
https://<project>.pages.dev - PR previews:
https://<branch>.<project>.pages.dev, also posted as a PR comment
Routing
Section titled “Routing”miamis a single-page app with client-side routing, so it shipspublic/_redirectswith/* /index.html 200. This is required or deep links like/worldreturn 404.newsstandis multi-page (index.html,controller.html,screen.html,simulator.html), so each page is served directly and no redirects file is needed.docsanddesignare static multi-page builds and need no redirects.
Versions
Section titled “Versions”- Node comes from
.nvmrcat the repo root (currently22). The workflow reads it; Cloudflare is not building, so only the workflow matters. - pnpm comes from the
packageManagerfield in the rootpackage.json.
Adding a new app
Section titled “Adding a new app”- Create the app folder in
apps/<name>with abuildscript that outputs todist. - Create a Cloudflare Pages project named
mars-<name>(Direct Upload, production branchmain). - Add an entry to the matrix in
.github/workflows/deploy.yml:- app: <name>project: mars-<name> - Add the custom domain
<name>.esimm.appin the project settings.