Migrate to Maritime

Move the automation layer of your cloud onto Maritime agents: cron jobs, scheduled functions, background workers, and bots. Each guide below inventories a provider with read-only credentials, recreates every workload as a Maritime agent with a schedule and encrypted env vars, verifies it end to end, and only then hands you a reversible cutover checklist. Hosting is a flat price per agent per month (see Billing & plans), and auto-sleep means a cron agent costs the same whether it runs for one second or one hour.

The safety model, in one box. Inventory runs on read-only credentials you mint for the occasion. Credentials travel through env vars, never chat. Nothing on the source provider is modified or deleted by an agent, ever: cutover is a checklist you run yourself, and every checklist starts with a reversible step (disable, pause, scale to zero) before any delete. Both sides run in parallel until you are satisfied.

How every migration works

All ten guides follow the same five steps. They are written to be followed by a coding agent (point Claude Code or your Maritime agent at one) or by a human in a terminal.

  1. Inventory: sweep the provider with its own CLI and read-only credentials, and list everything agent-shaped: things that wake up, do a job, and go quiet.
  2. Map: schedule expressions become cron triggers, env vars and secrets become encrypted agent env vars, logs become maritime logs.
  3. Recreate: an LLM-driven bot lands on a framework template; arbitrary code lands as a bring-your-own container from your repo. Porting a serverless function into a container is real work, and the guides say so instead of pretending.
  4. Verify: the new agent must do the job at least once, checked against a known-good run, while the old side is still untouched.
  5. Cut over: disable the old schedule (reversible), watch for a few days, then delete, in that order, with your own credentials.
npm i -g maritime-cli && maritime login
maritime keys create --name migration --json   # mk_... shown once
export MARITIME_TOKEN=mk_...

maritime templates --json                      # pick a template id from the live list
maritime create nightly-report --template <id> --json
maritime env import nightly-report ./old-provider.env --reload --json
maritime chat nightly-report "run your task once now and report" --json

Schedules are recreated as cron triggers on the agent page (see Triggers). One gotcha worth knowing up front: timers inside a sleeping VM do not fire, so scheduled work belongs in a trigger, not in an in-process scheduler, unless the agent is always-on.

Migrate from AWS

What moves: Scheduled Lambda functions, EventBridge cron rules, ECS scheduled tasks, and bots or workers running on EC2 instances. Lambda env vars, Secrets Manager entries, and SSM parameters become encrypted agent env vars.

# Inventory with a read-only IAM user (ReadOnlyAccess policy)
aws events list-rules --query 'Rules[?ScheduleExpression!=null].[Name,ScheduleExpression,State]' --output table
aws lambda list-functions --query 'Functions[].[FunctionName,Runtime]' --output table

EventBridge cron has six fields with ? placeholders; Maritime triggers use standard five-field cron. cron(0 12 * * ? *) becomes 0 12 * * *, and rate(5 minutes) becomes */5 * * * *.

What stays: S3, DynamoDB, RDS, and Route 53 stay on AWS. Your agent keeps calling them with scoped credentials. VPC-only resources (a private RDS, anything without a public endpoint) are unreachable from Maritime, so flag those before deciding.

Migrate from Google Cloud

What moves: Cloud Scheduler jobs, scheduled Cloud Functions, Cloud Run jobs, and bots on Compute Engine. Secret Manager values move into encrypted agent env vars. Cloud Scheduler already uses five-field cron plus a timezone, so schedules map nearly 1:1.

# Inventory with a service account holding roles/viewer
gcloud scheduler jobs list --location=us-central1
gcloud functions list && gcloud run jobs list

What stays: Cloud Storage, Cloud SQL, BigQuery, Firestore, and Cloud DNS stay. Keep using them from the agent over public endpoints. A Cloud SQL instance with only a private IP is unreachable from Maritime.

Migrate from Azure

What moves: Azure Functions with timer triggers, Container Apps jobs, Logic Apps automations, and bots on Azure VMs. Key Vault secrets move into encrypted agent env vars.

# Inventory with a service principal holding the Reader role
az functionapp list --output table
az containerapp job list --output table

Azure NCRONTAB has six fields including seconds. 0 0 12 * * * becomes 0 12 * * * on a Maritime trigger.

What stays: Blob Storage, Azure SQL, Cosmos DB, and Azure DNS stay. Service Bus consumers only move if the producer can hit a webhook instead, or the agent polls on a schedule. Private endpoints inside a VNet are unreachable from Maritime.

Migrate from Cloudflare

What moves: Workers on cron triggers, plus their KV and D1 data via export. A Worker that serves HTTP maps to a public web agent, but Workers runtime bindings (env.KV and friends) must become plain API calls, which is porting work.

# Inventory with a custom read-only API token (never the Global API Key)
npx wrangler deployments list
npx wrangler d1 export my-db --output dump.sql

What stays: Keep your DNS zones on Cloudflare, along with Pages sites and R2 buckets. R2 is S3-compatible, so the agent keeps using it directly. Durable Object alarms and Queues are Cloudflare-runtime constructs; moving those is a rewrite of the trigger model.

Migrate from Vercel

What moves: Cron jobs from vercel.json and the API routes they hit. The common case is moving only the crons and background work while the site stays on Vercel. Often the fastest path is recreating the cron logic as instructions to a framework agent rather than porting the route.

# Source of truth is your git repo: read the crons block in vercel.json
vercel project ls
vercel env pull .env.production --environment=production

Vercel tokens have no read-only scope, so run the migration locally where you are already logged in, and delete any token you mint for it afterward.

What stays: The Next.js site itself, plus Vercel Postgres, KV, and Blob. Copy connection strings into the agent env and keep using them. Domains and DNS stay.

Migrate from Heroku

What moves: Heroku Scheduler jobs, worker and clock dynos, and config vars. Scheduler only offers three frequencies, so real cron on a Maritime trigger is an upgrade. A worker that only reacts to events can auto-sleep, which usually costs less than an always-running dyno.

heroku apps --json
heroku ps -a my-app
heroku config -a my-app --shell   # write to a local .env, import, delete the file

Heroku Scheduler jobs are not listable from the CLI. Open the Scheduler add-on page in the dashboard and copy the jobs out. Heroku API keys are full-access, so mint a dedicated authorization and revoke it after.

What stays: Heroku Postgres and Redis add-ons stay: pull DATABASE_URL and REDIS_URL into the agent env and keep using them. The web dyno stays if it serves your site.

Migrate from Fly.io

What moves: Machines, including scheduled ones, and fly.toml worker processes. Fly apps are already containers with a Dockerfile, so pointing maritime create at the same repo is nearly direct. Fly schedule granularity (hourly, daily) upgrades to full cron on Maritime.

# Inventory with a read-only org token: fly tokens create readonly
fly apps list
fly machine list -a my-app && fly config show -a my-app

fly secrets list shows names and digests only. Secret values are not retrievable by design and must come from your own records.

What stays: Fly Postgres and volumes stay. A database that only listens on the private 6PN network is unreachable from Maritime, so it needs a public connection option or the workload stays put.

Migrate from Render

What moves: Cron job services (a cron expression plus a command, which maps 1:1 to an agent trigger) and background workers. Env groups and per-service env vars move into encrypted agent env vars.

# Source of truth: render.yaml in your repo, or the REST API
curl -s https://api.render.com/v1/services -H "Authorization: Bearer $RENDER_API_KEY"

Render API keys are full-account with no read-only scope, so run the migration locally and delete the key from your Render settings afterward.

What stays: Web services and static sites stay if they serve your site. Render Postgres and Key Value stay: use the external connection string from the agent, since internal-only URLs will not resolve from Maritime.

Migrate from DigitalOcean

What moves: App Platform workers and jobs, DO Functions with cron triggers, and bots on droplets (the droplet interior is the VPS guide below). App spec env values move into encrypted agent env vars.

# Inventory with a custom scoped token (read scopes only)
doctl apps list && doctl apps spec get <app-id>
doctl serverless triggers list

What stays: Spaces buckets are S3-compatible, so keep using them from the agent. Managed databases stay: use the public connection string and update trusted sources. VPC-only databases are unreachable from Maritime.

Migrate from a VPS

What moves: The classic case: a $5 box running your bot under tmux. Crontab lines, systemd services and timers, pm2 and supervisor processes, tmux and screen sessions, and Docker containers all inventory over SSH and land as agents with triggers.

ssh me@box 'crontab -l; systemctl list-timers; pm2 ls; tmux ls; docker ps'

There is no enforced read-only SSH, so the guide constrains the agent to an explicit list of read commands and leaves anything needing sudo to you.

What stays: Anything else on the box: a localhost Postgres or Redis, nginx sites, backups. Every localhost connection string in the env is a decision point, because localhost breaks when the worker moves. Check for other tenants before canceling the server.

See also

The full flag reference for maritime create lives in the CLI Reference. Triggers, env vars, and resource sizing are covered in Configuration. Bringing your own container? Read the custom framework contract first, especially the CMD rule.