Deploy CareLoom to a managed cloud platform without managing servers. This guide covers Railway (recommended) and Render.
A running CareLoom instance with:
- API service (Spring Boot) connected to a managed MySQL database
- Admin dashboard (React) accessible via browser
- Default admin account for initial setup
The mobile app is not deployed to the cloud. CHWs install it on their Android devices and point it at the API URL.
Estimated cost: ~$5-8/month (Hobby plan, varies with usage) Time: ~5 minutes
Railway provides managed MySQL and easy multi-service deploys from a mono-repo.
- Go to railway.app and sign in with GitHub
- Click New Project > Deploy from GitHub repo
- Select the
DHEPLab/careloomrepository (fork it first if needed)
- In your project dashboard, click New > Database > MySQL
- Railway auto-provisions the database and sets
MYSQL_*environment variables - Note: the database is empty at this point. The API will run Flyway migrations on first boot.
- Click New > GitHub Repo > select the same repo
- In the service settings:
- Root Directory:
services/api - Builder: Dockerfile
- Root Directory:
- Add these environment variables (Settings > Variables):
| Variable | Value |
|---|---|
SPRING_PROFILES_ACTIVE |
docker |
SPRING_DATASOURCE_URL |
jdbc:mysql://${{MySQL.MYSQLHOST}}:${{MySQL.MYSQLPORT}}/${{MySQL.MYSQLDATABASE}}?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf-8 |
SPRING_DATASOURCE_USERNAME |
${{MySQL.MYSQLUSER}} |
SPRING_DATASOURCE_PASSWORD |
${{MySQL.MYSQLPASSWORD}} |
JWT_SECRET_KEY |
Generate a strong random string (e.g., openssl rand -hex 32) |
- Set the Port to
8080 - Set the Health Check Path to
/actuator/health - Click Deploy
- Click New > GitHub Repo > select the same repo again
- In the service settings:
- Root Directory:
services/admin-web - Builder: Dockerfile
- Root Directory:
- Add this environment variable:
| Variable | Value |
|---|---|
API_URL |
http://careloom-api.railway.internal:8080 |
- Set the Port to
3000 - Click Deploy
- For each service, go to Settings > Networking > Generate Domain
- The admin dashboard URL is what you'll share with program managers
- The API URL is what you'll configure in the mobile app
Estimated cost: ~$14-21/month (two Starter instances + external MySQL) Time: ~10 minutes
You must provision MySQL separately. Options:
- PlanetScale (free tier available, MySQL-compatible)
- Aiven (free tier, managed MySQL)
- Any MySQL 5.7+ provider
- Create a MySQL 5.7+ database on your chosen provider
- Note the connection details: host, port, database name, username, password
- Go to render.com and sign in
- Click New > Blueprint
- Connect the
DHEPLab/careloomrepository - Render reads
render.yamland creates two services automatically
For the careloom-api service, set these environment variables manually:
| Variable | Value |
|---|---|
SPRING_DATASOURCE_URL |
jdbc:mysql://YOUR_HOST:3306/YOUR_DB?useSSL=true&characterEncoding=utf-8 |
SPRING_DATASOURCE_USERNAME |
Your MySQL username |
SPRING_DATASOURCE_PASSWORD |
Your MySQL password |
The JWT_SECRET_KEY is auto-generated by the Blueprint.
- Click Apply to deploy both services
- Wait for the API health check to pass (may take 1-2 minutes on first boot as Flyway runs migrations)
Log in to the admin dashboard with the default credentials (admin / admin) and immediately change the password.
CareLoom ships with no curriculum data. Use the admin dashboard to:
- Create a new Curriculum
- Add Modules with content components (text, media, switches)
- Assign the curriculum to a Project
Point the mobile app at your API URL:
- In
services/app, update the API endpoint configuration - Build the APK with
npx expo build:androidor use EAS Build - Distribute to CHWs
Both Railway and Render support custom domains:
- Railway: Settings > Networking > Custom Domain
- Render: Settings > Custom Domains
The first boot takes longer because Flyway runs all 62 database migrations. Wait 2-3 minutes and check logs. If it still fails, verify your database connection string.
Double-check SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD. On Railway, make sure you're using the ${{MySQL.MYSQLUSER}} variable reference, not a hardcoded value.
The API_URL environment variable must point to the API's internal URL (not the public URL). On Railway, use http://careloom-api.railway.internal:8080.
The mobile app needs the API's public URL (the one with the Railway/Render domain). Make sure CORS is configured if you're using a custom domain.