This guide covers deploying CryptoEats on multiple platforms. The application consists of an Express.js backend with PostgreSQL and an Expo React Native frontend.
- Prerequisites
- Environment Variables
- Vercel (Current Setup)
- Railway
- Render
- Fly.io
- DigitalOcean App Platform
- AWS Amplify + Elastic Beanstalk
- Google Cloud Run
- Heroku
- Replit
- Self-Hosted (VPS / Coolify)
- Mobile App Distribution
- Post-Deployment Checklist
- Node.js 20+ (22.x recommended)
- PostgreSQL 15+ database (Neon, Supabase, or any provider)
- Git repository (GitHub recommended for auto-deploy integrations)
- Domain name (optional, e.g., cryptoeats.net)
All platforms require these environment variables. Only DATABASE_URL is required to start. The rest enable optional features.
| Variable | Description | Example |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | postgresql://user:pass@host:5432/dbname?sslmode=require |
| Variable | Description | Used For |
|---|---|---|
SESSION_SECRET |
JWT signing secret (random 64+ char string) | Authentication |
STRIPE_SECRET_KEY |
Stripe API secret key | Payment processing |
STRIPE_WEBHOOK_SECRET |
Stripe webhook signing secret | Payment webhooks |
SENDGRID_API_KEY |
SendGrid API key | Email notifications |
TWILIO_ACCOUNT_SID |
Twilio account SID | SMS notifications |
TWILIO_AUTH_TOKEN |
Twilio auth token | SMS notifications |
TWILIO_PHONE_NUMBER |
Twilio phone number | SMS sender |
EXPO_ACCESS_TOKEN |
Expo push notification token | Push notifications |
PERSONA_API_KEY |
Persona API key | ID/age verification |
CHECKR_API_KEY |
Checkr API key | Driver background checks |
SENTRY_DSN |
Sentry error tracking DSN | Error monitoring |
REDIS_URL |
Redis connection string | Caching (falls back to in-memory) |
AWS_ACCESS_KEY_ID |
AWS access key | S3 file storage |
AWS_SECRET_ACCESS_KEY |
AWS secret key | S3 file storage |
AWS_S3_BUCKET |
S3 bucket name | S3 file storage |
COINBASE_COMMERCE_API_KEY |
Coinbase Commerce key | Crypto payments |
ADYEN_API_KEY |
Adyen API key | International payments |
SQUARE_ACCESS_TOKEN |
Square access token | POS payments |
Type: Serverless functions Best for: Simple deployments with automatic scaling Limitations: 300-second function timeout, cold starts, read-only filesystem
-
Connect Repository
- Go to vercel.com and import your GitHub repository
- Framework Preset: select "Other"
-
Configuration (already included in repo)
vercel.json— routes all requests to the serverless functionscripts/vercel-build.js— builds the API, runs migrations and seedserver/vercel-entry.ts— serverless-compatible Express entry point
-
Environment Variables
- Go to Settings → Environment Variables
- Add
DATABASE_URL(required) - Add any optional variables from the table above
-
Deploy
# Automatic: push to GitHub, Vercel deploys automatically git push origin main # Manual: using Vercel CLI npx vercel --prod
-
Custom Domain
- Go to Settings → Domains
- Add your domain and configure DNS records as shown
- Database migrations and seeding run during the build step (not at runtime)
- File uploads use
/tmpdirectory (temporary, cleared between invocations) - Disable Deployment Protection for production: Settings → Deployment Protection → Standard Protection
- The entry point is
server/vercel-entry.ts, notserver/index.ts
Type: Persistent server (always-on) Best for: Full-stack apps, no cold starts, built-in database Free tier: $5/month credit on Hobby plan
-
Create Project
- Go to railway.app and create a new project
- Choose "Deploy from GitHub repo" and select your repository
-
Add PostgreSQL
- Click "New" → "Database" → "PostgreSQL"
- Railway automatically creates
DATABASE_URLand connects it to your service
-
Configure Service
- Build Command:
npm install && npm run server:build - Start Command:
npm run server:prod - Or alternatively, Start Command:
NODE_ENV=production npx tsx server/index.ts
- Build Command:
-
Environment Variables
DATABASE_URLis set automatically if you added Railway PostgreSQL- Add any optional variables under the Variables tab
-
Custom Domain
- Go to your service → Settings → Networking → Custom Domain
- Add your domain and configure DNS
- No cold starts — server runs continuously
- Built-in PostgreSQL — no external database needed
- Auto-deploys from GitHub on every push
- WebSocket support for real-time tracking and chat
- Persistent filesystem for file uploads
Type: Persistent server or static site Best for: Simple setup, free tier available, managed databases Free tier: 750 hours/month for web services (spins down after inactivity)
-
Create Web Service
- Go to render.com and click "New" → "Web Service"
- Connect your GitHub repository
- Environment: Node
- Build Command:
npm install && npm run server:build - Start Command:
npm run server:prod - Environment Variables: Add
PORT=5000(Render needs to know which port to proxy)
-
Add PostgreSQL
- Click "New" → "PostgreSQL"
- Copy the Internal Database URL
- Add as
DATABASE_URLin your web service environment variables
-
Environment Variables
- Add
DATABASE_URL(from step 2) - Add
NODE_ENV=production - Add any optional variables under Environment tab
- Add
-
Run Migrations and Seed (first deploy only)
- After the first deploy, go to your service → Shell
npx drizzle-kit push npm run db:seed
-
Custom Domain
- Go to Settings → Custom Domains
- Add domain and configure DNS
- Health Check Path:
/health - Auto-Deploy: Yes (from main branch)
- Plan: Starter ($7/month) or Free (spins down after 15min inactivity)
Type: Containers deployed globally (edge computing) Best for: Low latency worldwide, WebSocket support, persistent volumes Free tier: 3 shared VMs, 3GB persistent storage
-
Install Fly CLI
curl -L https://fly.io/install.sh | sh fly auth login -
Create App
fly launch --name cryptoeats
When prompted:
- Choose Miami (mia) region for lowest latency
- Select "Yes" for PostgreSQL database
- It will create a
fly.tomlfile
-
Configure
fly.tomlCreate or update this file in your project root:app = "cryptoeats" primary_region = "mia" [build] [build.args] NODE_VERSION = "22" [env] NODE_ENV = "production" PORT = "8080" [http_service] internal_port = 8080 force_https = true auto_stop_machines = true auto_start_machines = true [[vm]] cpu_kind = "shared" cpus = 1 memory_mb = 512
-
Create Dockerfile
FROM node:22-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --production=false COPY . . RUN npm run server:build RUN npx drizzle-kit push EXPOSE 8080 ENV PORT=8080 CMD ["npm", "run", "server:prod"]
-
Set Secrets
fly secrets set DATABASE_URL="postgresql://..." fly secrets set SESSION_SECRET="your-secret-here"
-
Deploy
fly deploy
-
Custom Domain
fly certs create cryptoeats.net
Then add the CNAME record to your DNS.
Type: Managed platform (PaaS) Best for: Simple deployment with managed infrastructure Pricing: Starting at $5/month for basic tier
-
Create App
- Go to cloud.digitalocean.com → Apps → Create App
- Connect your GitHub repository
- Component Type: Web Service
-
Configure Build & Run
- Build Command:
npm install && npm run server:build - Run Command:
npm run server:prod - HTTP Port: 5000
- Build Command:
-
Add Database
- Click "Add Resource" → "Database" → "PostgreSQL"
- DigitalOcean auto-injects
DATABASE_URL
-
Environment Variables
- Add optional variables under App Settings → Environment Variables
-
Deploy
- Click "Deploy" — auto-deploys from GitHub on push
-
Custom Domain
- Go to Settings → Domains → Add Domain
- Configure DNS with the provided CNAME
Type: Elastic Beanstalk (managed servers) or ECS (containers) Best for: Enterprise scale, full AWS ecosystem integration Pricing: Pay-as-you-go, free tier for 12 months
-
Install EB CLI
pip install awsebcli eb init
-
Create
.ebextensions/nodecommand.configoption_settings: aws:elasticbeanstalk:container:nodejs: NodeCommand: "npm run server:prod"
-
Create Environment
eb create cryptoeats-prod --envvars DATABASE_URL=postgresql://...
-
Add RDS PostgreSQL
- In AWS Console → RDS → Create Database → PostgreSQL
- Copy the endpoint and update
DATABASE_URL
-
Deploy
eb deploy
-
Custom Domain
- Use Route 53 or your DNS provider
- Point domain to the Elastic Beanstalk URL
Type: Serverless containers Best for: Auto-scaling, pay-per-request, Google Cloud ecosystem Free tier: 2 million requests/month
-
Install Google Cloud CLI
gcloud auth login gcloud config set project your-project-id -
Create
Dockerfile(same as Fly.io section above) -
Create Cloud SQL PostgreSQL
gcloud sql instances create cryptoeats-db \ --database-version=POSTGRES_15 \ --tier=db-f1-micro \ --region=us-east1
-
Build and Deploy
gcloud run deploy cryptoeats \ --source . \ --region us-east1 \ --allow-unauthenticated \ --set-env-vars DATABASE_URL="postgresql://..." \ --port 8080
-
Custom Domain
gcloud run domain-mappings create \ --service cryptoeats \ --domain cryptoeats.net \ --region us-east1
Type: Managed platform (PaaS) Best for: Simplest deployment, many add-ons available Pricing: Starting at $5/month (Eco dynos)
-
Install Heroku CLI
npm install -g heroku heroku login
-
Create App
heroku create cryptoeats
-
Add PostgreSQL
heroku addons:create heroku-postgresql:essential-0
This automatically sets
DATABASE_URL. -
Create
Procfilein project root:web: npm run server:prod release: npx drizzle-kit push && npx tsx scripts/run-seed.ts -
Set Environment Variables
heroku config:set SESSION_SECRET="your-secret" heroku config:set NODE_ENV=production -
Deploy
git push heroku main
-
Custom Domain
heroku domains:add cryptoeats.net
Then add the DNS target as a CNAME record.
Type: Cloud development and hosting platform Best for: Development + deployment in one place, instant setup Pricing: Free tier available, Deployments start at Core plan
-
Development (already configured)
- Backend runs via the "Start Backend" workflow:
npm run server:dev - Frontend runs via the "Start Frontend" workflow:
npm run expo:dev - PostgreSQL database is built-in and auto-configured via
DATABASE_URL
- Backend runs via the "Start Backend" workflow:
-
Publishing to Production
- Click the "Publish" button in the Replit workspace
- Choose deployment type: "Reserved VM" (recommended for this app — always-on server with WebSocket support)
- Build Command:
npm install && npm run server:build - Run Command:
npm run server:prod
-
Custom Domain
- After publishing, go to the Deployments tab → Settings
- Click "Link a domain" and enter your custom domain
- Add the A record and TXT record provided to your domain's DNS settings
- SSL certificates are provisioned automatically
-
Environment Variables
DATABASE_URLis already set automatically- Add any optional variables via the Secrets tab in the sidebar
- No separate database setup needed (built-in PostgreSQL)
- Edit code and see changes instantly
- Automatic checkpoints for rollback
- Built-in secrets management
Type: Your own server Best for: Full control, no platform fees, data sovereignty Providers: DigitalOcean Droplet, Linode, Hetzner, AWS EC2, any VPS
-
Provision a Server
- Ubuntu 22.04+ recommended
- Minimum: 1 vCPU, 1GB RAM
- Recommended: 2 vCPU, 2GB RAM
-
Install Dependencies
# Node.js 22 curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - sudo apt install -y nodejs # PostgreSQL sudo apt install -y postgresql postgresql-contrib sudo -u postgres createuser cryptoeats -P sudo -u postgres createdb cryptoeats -O cryptoeats # Nginx (reverse proxy) sudo apt install -y nginx certbot python3-certbot-nginx
-
Clone and Build
git clone https://github.com/your-username/crypto-eats.git cd crypto-eats npm install npm run server:build -
Set Environment Variables
# Create .env file cat > .env << EOF DATABASE_URL=postgresql://cryptoeats:yourpassword@localhost:5432/cryptoeats SESSION_SECRET=$(openssl rand -hex 32) NODE_ENV=production PORT=5000 EOF
-
Run Migrations and Seed
npx drizzle-kit push npx tsx scripts/run-seed.ts
-
Configure Nginx
# /etc/nginx/sites-available/cryptoeats server { listen 80; server_name cryptoeats.net www.cryptoeats.net; location / { proxy_pass http://127.0.0.1:5000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cache_bypass $http_upgrade; } }
sudo ln -s /etc/nginx/sites-available/cryptoeats /etc/nginx/sites-enabled/ sudo nginx -t && sudo systemctl reload nginx -
SSL Certificate
sudo certbot --nginx -d cryptoeats.net -d www.cryptoeats.net
-
Process Manager (keep server running)
sudo npm install -g pm2 pm2 start npm --name cryptoeats -- run server:prod pm2 save pm2 startup
If you want a Vercel-like dashboard on your own server:
-
Install Coolify on your VPS:
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -
Add Your Server in the Coolify dashboard
-
Create New Resource → Application → Connect GitHub repo
-
Configure:
- Build Command:
npm install && npm run server:build - Start Command:
npm run server:prod - Port: 5000
- Build Command:
-
Add PostgreSQL as a database resource in Coolify
-
Deploy — Coolify handles SSL, domains, and auto-deploys
The Expo mobile app connects to whichever backend URL you deploy. Update the API URL in your app configuration:
In your Expo app environment config, set the backend URL to your deployed server:
EXPO_PUBLIC_API_URL=https://cryptoeats.net
# Install EAS CLI
npm install -g eas-cli
eas login
# Build APK for sideloading
eas build --platform android --profile preview
# Build AAB for Play Store
eas build --platform android --profile production# Build for TestFlight / App Store
eas build --platform ios --profile productionAfter deploying to any platform, verify these items:
- Visit your URL — landing page loads
- Check
/health— returns{ "status": "healthy" } - Check
/admin— admin dashboard loads - Check
/merchant— merchant dashboard loads - Check
/api-docs— API documentation loads - Check
/developers— developer portal loads
- Register a new account via
/api/auth/register - Login via
/api/auth/login - Verify JWT tokens are issued correctly
- Confirm seed data loaded (restaurants, menus visible in admin)
- Create a test order
- Verify order appears in admin dashboard
-
SESSION_SECRETis set to a strong random value (not the default) - HTTPS is enabled and HTTP redirects to HTTPS
- CORS is configured for your domain
- Rate limiting is active on auth endpoints
- Stripe payments processing (if
STRIPE_SECRET_KEYset) - Email notifications (if
SENDGRID_API_KEYset) - SMS notifications (if Twilio credentials set)
- Push notifications (if
EXPO_ACCESS_TOKENset) - Error monitoring (if
SENTRY_DSNset)
| Platform | Type | Cold Starts | WebSockets | Built-in DB | Free Tier | Starting Price |
|---|---|---|---|---|---|---|
| Vercel | Serverless | Yes | No | No | Yes | $0 (Hobby) |
| Railway | Persistent | No | Yes | Yes | $5 credit | $5/mo |
| Render | Persistent | On free tier | Yes | Yes | Yes | $0 (Free) |
| Fly.io | Container | Optional | Yes | Yes | Yes | $0 (3 VMs) |
| DigitalOcean | Managed | No | Yes | Yes | No | $5/mo |
| AWS | Various | Depends | Yes | Yes | 12 months | Pay-as-you-go |
| Google Cloud | Container | Optional | Yes | Yes | Yes | Pay-as-you-go |
| Heroku | Managed | On Eco | Yes | Yes | No | $5/mo |
| Replit | Managed | No | Yes | Yes | Yes | Core plan |
| Self-hosted | Full control | No | Yes | Yes | N/A | ~$5/mo VPS |
Recommendation for CryptoEats: Railway or Render for the simplest full-stack experience with WebSocket support, persistent server, and built-in database. Use Vercel if you prefer serverless with separate database hosting.