Deploy to Fly.io
Deploy your Motia app to Fly.io with Upstash Redis for global edge deployment
Fly.io runs your app on fast micro-VMs close to your users. Combined with Upstash Redis, you get a globally distributed Motia backend.
This guide walks you through deploying a Motia app to Fly.io with production Redis.
What you'll get: A containerized Motia app running on Fly.io with Upstash Redis for state, events, streams, and cron locking.
Example Project: Follow along with the Todo App example - a complete deployment-ready Motia app with Redis configuration.
Prerequisites
Before you start:
- A Fly.io account (free tier works)
- Fly CLI installed
- Docker running locally (for testing)
- A Motia project ready to deploy
Install the Fly CLI:
Login:
Quick Start
Add Upstash Redis
Follow the prompts to create a Redis instance. Choose a region close to your app.
Upstash Redis on Fly requires a credit card on file, even for free tier usage.
Set environment variables
The Redis URL is automatically attached when you create Redis with flyctl redis create.
Get your URL
Your app is live at: https://my-motia-app.fly.dev
Project Setup
Update Your Start Script
Fly injects the port via environment variables. Update your package.json:
The --host 0.0.0.0 is important - Fly needs your app to listen on all interfaces.
Configure Redis
Motia supports two approaches for production Redis configuration:
Option 1: Simple Redis Config (Recommended)
Use Motia's built-in redis configuration option:
That's it! The config parses REDIS_URL automatically. Fly sets this when you run flyctl redis create.
Option 2: Custom Adapters (Advanced)
For more control over individual adapters:
Fly.io vs Railway
| Feature | Fly.io | Railway |
|---|---|---|
| Global regions | 30+ regions | Limited regions |
| Redis | Upstash (external) | Built-in Redis |
| Pricing | Pay-per-use | Usage-based |
| CLI | flyctl | railway |
| Best for | Edge deployment | Simple setup |
Choose Fly.io if you need low-latency responses globally. Choose Railway for simpler Redis setup.
Common Commands
Troubleshooting
App Not Listening on Expected Address
Symptom: Fly warns "app is not listening on the expected address"
Fix: Make sure your start script includes --host 0.0.0.0:
Redis Connection Refused
Symptom: Logs show ECONNREFUSED 127.0.0.1:6379
Cause: App is trying to connect to local Redis instead of Upstash.
Fix:
- Check if
REDIS_URLis set:flyctl secrets list - Create Redis if missing:
flyctl redis create - Verify your config parses the URL correctly
TLS Connection Errors
Symptom: Redis connection fails with TLS/SSL errors
Cause: Upstash requires TLS (rediss://), but your config isn't enabling it.
Fix: Make sure your config enables TLS when the protocol is rediss://:
Plugin Not Loading
Cause: Plugin imports might not be resolving correctly.
Fix: Use ESM imports (recommended for "type": "module" projects):
Machine Keeps Restarting
Symptom: App restarts repeatedly in logs
Common causes:
- Unhandled exceptions during startup
- Missing environment variables
- Port binding issues
Debug: Check logs for the actual error:
Scaling Globally
Fly makes global deployment easy. Add machines in different regions:
With Redis configured, all machines share state automatically. Users connect to the nearest machine for lowest latency.
What's Next?
Deploy to Railway
Alternative with simpler Redis setup
Self-Hosted
Full control with your own infrastructure