Complete guide for deploying PlotPulse backend to Railway with PostGIS database.
npm i -g @railway/cliplot-pulse)⚠️ CRITICAL: Railway needs to know where your Dockerfile is.
backendbackend/DockerfileImportant: Use PostGIS, NOT regular PostgreSQL!
Option A: Using Railway CLI (Recommended)
# Connect to PostGIS
railway connect postgis
# In psql prompt, run:
CREATE EXTENSION IF NOT EXISTS postgis;
CREATE EXTENSION IF NOT EXISTS postgis_topology;
# Verify:
\dx
# Exit:
\q
Option B: Using Railway Dashboard
PGHOST = postgis.railway.internal (for internal connection)PGPORT = 5432PGDATABASE = railway (default database name)PGUSER = postgresPOSTGRES_PASSWORD = (copy this value - this is the actual password)Option A: Add Reference (If Available)
Option B: Manual Setup (If Reference Not Available)
| Variable | Value |
|---|---|
PGHOST |
postgis.railway.internal |
PGPORT |
5432 |
PGDATABASE |
railway |
PGUSER |
postgres |
PGPASSWORD |
(copy from PostGIS POSTGRES_PASSWORD) |
In plot-pulse service → “Variables” tab, add:
| Variable | Value | Notes |
|---|---|---|
SPRING_PROFILES_ACTIVE |
prod,railway |
REQUIRED - Use prod,railway to enable Railway-specific overrides |
JWT_SECRET |
(generate secure secret) | REQUIRED - See below |
FRONTEND_URL |
https://plotpulse.syrez.co.in |
Optional - for CORS |
Note: Using prod,railway profile enables Railway-specific configurations:
0.0.0.0 (required for Railway networking)PORT environment variable (Railway’s convention)railway (Railway’s default database name)disable for internal connections (Railway’s internal network)Generate JWT_SECRET:
# PowerShell
[Convert]::ToBase64String((1..64 | ForEach-Object { Get-Random -Minimum 0 -Maximum 256 }))
Or use this pre-generated one (for testing only - generate new for production):
5Bm9beXKU/sYEBBVJiho28/hBb2BmRWnLYxHUa7KdAIY8y73tBBmJSnSLHPNsQt4Io1L2MM0qU7qmgELBr9eoQ==
Your plot-pulse service should have:
✅ SPRING_PROFILES_ACTIVE=prod,railway (use prod,railway to enable Railway-specific overrides)
✅ JWT_SECRET (secure value)
✅ PGHOST=postgis.railway.internal
✅ PGPORT=5432
✅ PGDATABASE=railway
✅ PGUSER=postgres
✅ PGPASSWORD (from PostGIS)
This is the most common issue causing 502 errors!
PORT environment variable🚀 Server started successfully! Listening on: 0.0.0.0:XXXX8080)PORT environment variable automatically
server.port: ${PORT:${SERVER_PORT:8091}}PORT automatically - don’t override it manuallyplot-pulse-production.up.railway.apphttps://plot-pulse-production.up.railway.app/api/v1Go to plot-pulse → Deployments → Latest deployment → View logs
Success indicators:
🚀 Server started successfully!
Listening on: 0.0.0.0:8080
Context path: /api/v1
Started ProjectApplication in XX seconds
Error indicators:
Connection to localhost:5432 refused → Database variables not setCould not resolve placeholder 'JWT_SECRET' → JWT_SECRET not setUnsupported Database: PostgreSQL 16.9 → Flyway PostgreSQL driver missing (should be fixed)Open in browser:
https://plot-pulse-production.up.railway.app/api/v1/health{"status":"SUCCESS","message":"Application is running",...}frontend/.env.development:
VITE_API_BASE_URL=https://plot-pulse-production.up.railway.app/api/v1
cd frontend
npm run dev
Cause: Port mismatch between Railway networking and backend
Solution:
🚀 Server started successfully! Listening on: 0.0.0.0:XXXXPORT env var8080)Important: Backend uses ${PORT} environment variable. Railway sets this automatically - don’t override it manually.
Cause: Database variables not set or wrong values
Solution:
PG* variables are set in plot-pulse servicepostgis.railway.internal for PGHOST (internal connection)POSTGRES_PASSWORD value from PostGIS service (not PGPASSWORD)Cause: JWT_SECRET environment variable not set
Solution:
JWT_SECRET with a secure valueCause: Flyway migrations not running
Solution:
spring.flyway.enabled=true in application-prod.ymlpom.xml:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>10.20.1</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
<version>10.20.1</version>
</dependency>
backend/src/main/resources/db/migration/Cause: CORS not configured or origin not allowed
Solution:
http://localhost:5173 is in application-prod.yml CORS allowed-originsCause: Flyway version doesn’t support PostgreSQL 16
Solution:
pom.xml:
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
<version>10.20.1</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
<version>10.20.1</version>
</dependency>
Cause: Railway can’t find build configuration
Solution:
backendCause: Dockerfile paths incorrect for Railway build context
Solution:
COPY backend/pom.xml ./pom.xml and COPY backend/src/ ./src/Cause: Maven tests failing during Docker build
Solution:
-Dmaven.test.skip=truecd backend && mvn test to fix them# Connect to PostGIS
railway connect postgis
# Now you're in psql - run SQL commands directly
SELECT * FROM users;
\q # to exit
shortline.proxy.rlwy.net (external) or postgis.railway.internal (internal)34889 (external) or 5432 (internal)railwaypostgresPOSTGRES_PASSWORD)backendpostgis, postgis_topology)PGHOST=postgis.railway.internalPGPORT=5432PGDATABASE=railwayPGUSER=postgresPGPASSWORD (from PostGIS)SPRING_PROFILES_ACTIVE=prodJWT_SECRET (secure value)/api/v1/health.env.development updated with Railway URLpostgis.railway.internal) for faster connectionsrailway by default (Railway’s convention)localhost:5173 - add production domains when readyAfter successful deployment: