Fly.io is a platform for running full-stack applications globally. It deploys your app close to users by running instances in multiple regions worldwide, providing low latency and high availability.
Why Fly.io?#
Perfect for Revali applications:
- Global Edge Deployment - Deploy to 30+ regions worldwide
- Automatic HTTPS - Free SSL certificates with automatic renewal
- Zero-Downtime Deploys - Rolling deployments with health checks
- Built-in Services - PostgreSQL, Redis, and more
- Generous Free Tier - 3 shared VMs with 256MB RAM each
- Simple Scaling - Add regions or increase resources with one command
Prerequisites#
Before deploying to Fly.io, ensure you have:
- ✅ A Revali application with generated Dockerfile (
dart run revali build) - ✅ Git repository (recommended for version control)
- ✅ Fly.io account (free to create)
- ✅ Fly CLI installed
Installation#
1. Create a Fly.io Account#
Sign up for a free account at fly.io/app/sign-up.
You'll need to:
- Verify your email
- Add a credit card (required for identity verification, free tier available)
2. Install flyctl CLI#
The Fly CLI (flyctl) is required for deployment.
macOS:
# Using Homebrew (recommended)
brew install flyctl
# Using install script
curl -L https://fly.io/install.sh | sh
Linux:
curl -L https://fly.io/install.sh | sh
Windows:
# Using PowerShell
iwr https://fly.io/install.ps1 -useb | iex
Verify installation:
flyctl version
3. Authenticate#
Log in to your Fly.io account:
flyctl auth login
This opens your browser for authentication.
Initial Setup#
1. Generate Dockerfile#
If you haven't already, generate your Dockerfile:
dart run revali build --release
This creates .revali/build/Dockerfile.
2. Move Dockerfile to Project Root#
Fly.io expects the Dockerfile in your project root:
cp .revali/build/Dockerfile ./Dockerfile
3. Initialize Fly App#
Run the launch command to create your Fly app:
flyctl launch
This interactive command will:
- Detect your Dockerfile
- Suggest an app name
- Select a region
- Offer to set up PostgreSQL (optional)
- Generate a
fly.tomlconfiguration file
Example interaction:
? Choose an app name (leave blank to generate one): my-revali-app
? Choose a region for deployment: Los Angeles, California (US) (lax)
? Would you like to set up a Postgresql database now? No
? Would you like to set up an Upstash Redis database now? No
? Would you like to deploy now? No
Configuration#
Understanding fly.toml#
The fly.toml file configures your Fly.io application. Here's an optimized configuration for Revali:
# App name (must be unique across Fly.io)
app = 'my-revali-app'
# Primary region (closest to most users)
primary_region = 'lax'
# Build configuration
[build]
# Dockerfile path (default: ./Dockerfile)
# Uncomment if you keep it in .revali/build/
# dockerfile = ".revali/build/Dockerfile"
# HTTP service configuration
[http_service]
# Port your app listens on
internal_port = 8080
# Force HTTPS
force_https = true
# Auto stop/start machines to save costs
auto_stop_machines = 'stop'
auto_start_machines = true
# Minimum running machines (0 = scale to zero when idle)
min_machines_running = 0
# Health check configuration
[http_service.concurrency]
type = "requests"
hard_limit = 250
soft_limit = 200
# VM configuration
[[vm]]
memory = '512mb' # Start small, scale up as needed
cpu_kind = 'shared' # Use 'performance' for dedicated CPUs
cpus = 1
Configuration Options Explained#
App Settings
app = 'my-revali-app' # Unique app name
primary_region = 'lax' # Primary deployment region
Available regions:
lax- Los Angelessjc- San Joseord- Chicagoiad- Ashburn, VAlhr- Londonfra- Frankfurtsyd- Sydney- See all regions
HTTP Service
[http_service]
internal_port = 8080 # Match your app's PORT
force_https = true # Redirect HTTP to HTTPS
auto_stop_machines = 'stop' # Stop when idle
auto_start_machines = true # Start on request
min_machines_running = 0 # Scale to zero
VM Resources
[[vm]]
memory = '512mb' # Options: 256mb, 512mb, 1gb, 2gb, 4gb, 8gb
cpu_kind = 'shared' # Options: shared, performance
cpus = 1 # Number of CPUs
Resource recommendations:
| Traffic Level | Memory | CPUs | Cost/Month |
|---|---|---|---|
| Development | 256mb | 1 | Free |
| Low Traffic | 512mb | 1 | ~$5 |
| Medium Traffic | 1gb | 1-2 | ~$10-15 |
| High Traffic | 2gb+ | 2-4 | ~$30+ |
Deployment#
First Deployment#
Deploy your application:
flyctl deploy
This will:
- Build your Docker image
- Push to Fly's registry
- Create machines in your selected region
- Run health checks
- Route traffic to your app
Expected output:
==> Building image
...
--> Building image done
==> Pushing image to fly
...
--> Pushing image done
==> Creating release
--> Release created
==> Deploying
--> Deploying done
View Your App#
Open your deployed application:
flyctl apps open
Or visit: https://my-revali-app.fly.dev
Environment Variables and Secrets#
Setting Secrets#
Store sensitive data as secrets:
# Set individual secrets
flyctl secrets set API_KEY=your_api_key_here
flyctl secrets set DATABASE_URL=postgresql://...
# Set multiple secrets at once
flyctl secrets set \
API_KEY=your_key \
JWT_SECRET=your_secret \
STRIPE_KEY=sk_live_...
Setting Environment Variables#
For non-sensitive configuration:
[env]
PORT = "8080"
LOG_LEVEL = "info"
ENVIRONMENT = "production"
Accessing in Your App#
import 'dart:io';
void main() {
final apiKey = Platform.environment['API_KEY']!;
final port = int.parse(Platform.environment['PORT'] ?? '8080');
final logLevel = Platform.environment['LOG_LEVEL'] ?? 'info';
}
Database Setup#
PostgreSQL#
Create a Fly PostgreSQL database:
flyctl postgres create
Follow the prompts:
? Choose an app name: my-app-db
? Select region: Los Angeles, California (US) (lax)
? Select configuration: Development - Single node, 1x shared CPU, 256MB RAM, 1GB disk
Connect to your app:
flyctl postgres attach my-app-db
This sets a DATABASE_URL secret automatically.
Use in your app:
import 'package:postgres/postgres.dart';
final databaseUrl = Platform.environment['DATABASE_URL']!;
final connection = await Connection.open(
Endpoint.fromUri(Uri.parse(databaseUrl)),
);
Redis#
Create a Redis instance with Upstash:
flyctl redis create
Connect to your app:
flyctl redis attach
This sets REDIS_URL automatically.
Scaling#
Horizontal Scaling#
Add more machines:
# Scale to 3 machines
flyctl scale count 3
# Scale to specific count per region
flyctl scale count 2 --region lax
flyctl scale count 1 --region lhr
Vertical Scaling#
Increase VM resources:
# Increase memory
flyctl scale memory 1024
# Increase CPUs
flyctl scale vm shared-cpu-2x
Multi-Region Deployment#
Deploy to multiple regions for global coverage:
# Add a region
flyctl regions add lhr # London
flyctl regions add fra # Frankfurt
flyctl regions add syd # Sydney
# List current regions
flyctl regions list
# Set machine count per region
flyctl scale count 2 --region lax
flyctl scale count 2 --region lhr
flyctl scale count 1 --region fra
Monitoring and Logs#
View Logs#
# Stream live logs
flyctl logs
# View recent logs
flyctl logs --recent
# Follow logs
flyctl logs -f
Application Status#
# Check app status
flyctl status
# View machine details
flyctl machines list
# Check app metrics
flyctl dashboard
Health Checks#
Configure health checks in fly.toml:
[http_service]
# ... other config ...
[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
timeout = "5s"
path = "/health"
Implement in your app:
@Get('/health')
Map<String, dynamic> healthCheck() {
return {
'status': 'healthy',
'timestamp': DateTime.now().toIso8601String(),
'version': '1.0.0',
};
}
Custom Domains#
Add a Domain#
flyctl certs create example.com
flyctl certs create www.example.com
Configure DNS#
Add these DNS records:
A @ 66.241.124.100
AAAA @ 2a09:8280:1::
A www 66.241.124.100
AAAA www 2a09:8280:1::
Or use a CNAME:
CNAME www my-revali-app.fly.dev
Verify Certificate#
flyctl certs show example.com
CI/CD Integration#
GitHub Actions#
Automate deployments with GitHub Actions:
name: Deploy to Fly.io
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dart-lang/setup-dart@v1
with:
sdk: stable
- name: Install dependencies
run: dart pub get
- name: Generate Dockerfile
run: dart run revali build --release
- name: Copy Dockerfile
run: cp .revali/build/Dockerfile ./Dockerfile
- name: Setup Fly CLI
uses: superfly/flyctl-actions/setup-flyctl@master
- name: Deploy to Fly.io
run: flyctl deploy --remote-only
env:
FLY_API_TOKEN: $
Setup:
-
Get your Fly.io API token:
flyctl auth token -
Add to GitHub Secrets:
- Go to repository Settings → Secrets → Actions
- Add
FLY_API_TOKENwith your token
Advanced Features#
Build Arguments#
Pass build arguments during deployment:
flyctl deploy --build-arg API_VERSION=v2
In Dockerfile:
ARG API_VERSION
RUN dart compile exe server.dart -DAPI_VERSION=$API_VERSION
Volume Mounts#
Create persistent storage:
# Create a volume
flyctl volumes create data --size 1 --region lax
# Configure in fly.toml
[[mounts]]
source = "data"
destination = "/app/data"
Private Networking#
Connect services within Fly's private network:
[env]
# Use .internal for private network DNS
REDIS_URL = "redis://my-redis.internal:6379"
Cost Optimization#
Free Tier#
Fly.io's free tier includes:
- 3 shared-cpu-1x VMs with 256MB RAM
- 160GB bandwidth per month
- Automatic HTTPS
Optimize for free tier:
[[vm]]
memory = '256mb'
cpu_kind = 'shared'
cpus = 1
[http_service]
min_machines_running = 0 # Scale to zero when idle
Cost-Saving Tips#
- Scale to zero: Set
min_machines_running = 0for development - Right-size VMs: Start small, scale up as needed
- Use auto-stop: Enable
auto_stop_machinesfor low-traffic apps - Consolidate regions: Start with one region, expand as needed
What's Next?#
- Deployment Overview - Explore other platforms
- Revali Build Command - Learn about build options