Deploying FudFi
FudFi deploys as three independently hosted pieces:
| Piece | Host | Project | Root directory |
|---|---|---|---|
| Backend API | Railway | fudfi / service backend | repo root |
| App | Vercel | fudfi-next | frontend |
| Marketing | Vercel | fudfi-landing | marketing |
Backend on Railway
Railway uses the Railpack builder, which builds the repo root as a monorepo and ignores most of railway.json. So the root package.json MUST have a start script and MUST NOT have a build script (otherwise Railpack tries to build the Next.js frontend for the backend and fails).
Root package.json requirements:
"start": "npm run start:backend"— exists today.- No root
buildscript. Web builds live infrontend/only. "engines": { "node": ">=20.9.0" }— Next 16 + Railpack’s default Node 18 otherwise.
Deploy:
railway up --service backendVerify the new code is live:
curl -X POST https://<backend-host>/api/auth/evm/challenge \
-H "Content-Type: application/json" -d '{}'
# expect HTTP 400 (validation), not 404Environment
DATABASE_URL=postgres://... # Railway Postgres proxy — NO ?sslmode= (db/client.js handles TLS)
ALLOWED_ORIGINS=https://app.fudfi.com,https://fudfi.com,https://www.fudfi.com,http://localhost:3001
NODE_ENV=production
GEMINI_API_KEY=...
HF_API_KEY=...
TWITTER_CLIENT_ID=... TWITTER_CLIENT_SECRET=... TWITTER_CALLBACK_URL=...
CLOUDINARY_CLOUD_NAME=... CLOUDINARY_API_KEY=... CLOUDINARY_API_SECRET=...
SOLANA_RPC_URL=https://api.mainnet-beta.solana.comRedis
The backend supports Redis via REDIS_URL and falls back to an in-memory cache. Production uses a Railway service named Redis, wired on backend as:
REDIS_URL=${{Redis.REDIS_URL}}Omit REDIS_URL locally; in-memory is fine.
App on Vercel
- Project
fudfi-next(teamteam_VOLeewSIrAYhkcVM9HBePF3N). Its Root Directory is baked tofrontendin project settings. - Deploy from the repo root (
vercel --prod), never from insidefrontend/. - Commits must be authored
fortunesayspump <fortuneze0@gmail.com>. Any other author gets the deployment blocked (seatBlock TEAM_ACCESS_REQUIRED). - The first
vercel --prodattempt often says “Not authorized” — just retry; it passes. - Custom domain:
vercel alias set <deployment-url> app.fudfi.com. - SSO protection must stay
deploymentType: preview; anything stricter wallsapp.fudfi.combehind a Vercel login page.
Required env on the project:
NEXT_PUBLIC_API_URL=https://backend-production-03de6.up.railway.app/
NEXT_PUBLIC_REOWN_PROJECT_ID=...
NEXT_PUBLIC_EVM_CHAIN=testnet # or mainnetDocs on Vercel
docs/ is a standalone Nextra app with its own package.json and package-lock.json. It is not part of the root npm workspaces. To host it, create a separate Vercel project with Root Directory = docs (install and build run inside docs/).
cd docs && npm install && npm run build # local verificationNative binaries (the recurring deploy killer)
This repo is developed on Windows but deployed on Linux. npm writes the lockfile for the local platform, so Linux-only native modules go missing remotely. If a deploy fails with Cannot find module '../*.node' or Could not load the "sharp" module, pin the Linux packages in optionalDependencies and regenerate the root lockfile:
- frontend:
lightningcss-linux-x64-gnu,@tailwindcss/oxide-linux-x64-gnu(Tailwind v4), plus@x402/core,@x402/evm,@x402/svm. - backend:
@img/sharp-linux-x64(pinned to sharp’s exact version).
After any dependency change:
npm install # at repo root
node -e "Object.keys(require('./package-lock.json').packages).filter(p=>/linux-x64/.test(p)).forEach(console.log)"
# commit BOTH package.json AND package-lock.jsonThere is intentionally no frontend/package-lock.json. Do not recreate it — it was stale and confused Next/Vercel. The root lockfile is the only lockfile.