Deploy UniSchema to the cloud
June 21, 2026 · View on GitHub
UniSchema ships as a single Docker image (API + admin UI). Pick a platform that supports persistent volumes for SQLite and secrets injection.
| Platform | Template | Persistent data |
|---|---|---|
| Fly.io | fly.toml | Fly volume → /app/data |
| Railway | railway.toml | Railway volume mount |
| Any container host | Dockerfile | Bind-mount or volume |
There is no official managed UniSchema SaaS in v0.2.0. These templates reduce ops burden; you still own secrets, S3, and vendor webhook URLs.
Minimum viable cloud (1–2 person advancement shop)
You do not need Airflow, Kubernetes, or Postgres to prove value.
| Component | Pilot choice | Skip for now |
|---|---|---|
| UniSchema app | Fly.io or Railway (free/low tiers) | Self-managed K8s |
| Database | SQLite on a platform volume | Postgres |
| Egress | S3 bucket (Terraform) | Airflow |
| Downstream | Notebook or Python script | Full warehouse |
Typical monthly cost (pilot): Fly/Railway ~$0–5 + S3 pennies + no Airflow.
Fastest path
fly launch --config deploy/fly.toml(or Railway from GitHub)terraform applyindeploy/terraform/s3-egress/for the bucket- Set secrets from
.env.example(webhook secrets + S3 creds) BASE_URL=https://your-app.fly.dev npm run demo- Open egress_report.ipynb for a stakeholder-friendly chart
Operator details: docs/operator-guide.md
Prerequisites (all platforms)
- S3 bucket (recommended) or accept local egress on a volume
- Webhook secrets from GiveCampus / Cvent dashboards
MAPPING_SYNC_TOKEN— long random string for canvas sync- AWS credentials (if
EGRESS_TARGET=s3) — IAM user or instance role
Copy variables from .env.example. Set them as platform secrets, not in git.
Fly.io
One-time setup
# Install flyctl: https://fly.io/docs/hands-on/install-flyctl/
fly auth login
fly launch --no-deploy --config deploy/fly.toml
Create a volume for SQLite + local egress fallback:
fly volumes create unischema_data --size 1 --region ord
Attach secrets (example):
fly secrets set \
NODE_ENV=production \
SERVE_FRONTEND=true \
WEBHOOK_SIGNATURE_REQUIRED=true \
GIVECAMPUS_WEBHOOK_SECRET=... \
CVENT_WEBHOOK_SECRET=... \
MAPPING_SYNC_REQUIRED=true \
MAPPING_SYNC_TOKEN=... \
EGRESS_TARGET=s3 \
EGRESS_S3_BUCKET=your-bucket \
EGRESS_S3_PREFIX=constituent-events \
AWS_ACCESS_KEY_ID=... \
AWS_SECRET_ACCESS_KEY=... \
AWS_REGION=us-east-1
Deploy:
fly deploy --config deploy/fly.toml
Register webhooks: https://<your-app>.fly.dev/webhooks/givecampus
Health check: https://<your-app>.fly.dev/health
Railway
- New project → Deploy from GitHub repo
- Railway detects
railway.tomland builds from rootDockerfile - Add a volume mounted at
/app/data - Set environment variables from
.env.examplein the Railway dashboard - Generate domain → use as webhook base URL
Railway auto-assigns PORT; the Dockerfile respects PORT=3000.
Terraform
Full Terraform modules (VPC, RDS, etc.) are not included in v0.2.0 — most advancement pilots start with Fly/Railway + S3.
If you need IaC for AWS (ECS + RDS + S3), open an issue with your constraints; community contributions welcome.
Post-deploy verification
curl -sf https://<host>/health
curl -sf https://<host>/api/mappings/givecampus # 404 OK if no mapping yet
# From repo clone:
BASE_URL=https://<host> ./scripts/demo-webhook.sh
Then configure S3 lifecycle rules and downstream jobs — see examples/downstream/README.md.
Operator checklist: docs/operator-guide.md
Multi-instance production
When one Fly/Railway instance is not enough:
| Component | Requirement |
|---|---|
| Database | Postgres (DATABASE_URL) — shared ingestion state |
| Rate limits | REDIS_URL — shared IP buckets across instances |
| Ingest queue | Enabled by default with Postgres (pg-boss); disable with INGEST_QUEUE_ENABLED=false |
| Sessions | Sticky sessions optional for admin UI; API is stateless |
Fly.io example (2 machines)
fly postgres create
fly postgres attach --app your-unischema-app
fly secrets set REDIS_URL=redis://... MAPPING_SYNC_TOKEN=...
fly scale count 2 --app your-unischema-app
Deploy with deploy/fly.toml. All instances must share the same Postgres and Redis.
See docs/postgres.md and docs/benchmarks.md.