Back to blog

Kyma now runs on Cloudflare's edge

May 19, 20264 min read

Today Kyma's API was down for about 4 hours. By 11pm the same evening, we had moved Kyma's primary backend off the host that went down and onto Cloudflare's global edge.

This post explains what happened, what we did, what changed for you, and what we learned.

What happened

Kyma's backend was running on a single hosting provider (Railway). Their upstream cloud provider blocked their account around 2pm Pacific. From that moment until they restored access, every request to kymaapi.com/v1/* returned a 404 after a ten-second timeout. Dashboard pages spun on Loading. Agent CLIs received connection errors. The API was, by any practical measure, down.

What didn't go down: your data, your balance, your API keys, your usage history. All of that lives in Supabase and Upstash, which are independent of the backend host. The outage was about reaching the data, not about the data itself. No charges were lost. No credits disappeared. No keys were rotated.

But "your data is safe" doesn't help when nobody can call your API. We needed to be reachable. So we moved.

What we did

The natural reflex was to add a second host on standby (we were halfway through setting up Fly.io when we realized Fly was also having problems, because Railway and Fly both depend on the same upstream cloud). Adding a second host on the same upstream isn't diversification. It's coincidence insurance.

Cloudflare Workers runs on Cloudflare's own infrastructure, which is independent of the upstream that took Railway down. So we pivoted.

Over the next 4 hours we built a Cloudflare Workers version of Kyma's backend from scratch, deployed it in phases, and switched all of kymaapi.com and api.kymaapi.com over to it. By 6:30pm the production traffic path was running on Workers. By 10pm it covered every customer-facing endpoint: chat completions, the Anthropic Messages shape, login and signup (Google + email), Stripe checkout and webhook, billing, usage, the rate-limit ladder. By 11pm it was the documented primary, with Railway acting as a warm standby.

We shipped 18 pull requests in that window. Two were closed (one was the Fly cold-standby idea we abandoned mid-flight). Sixteen were merged.

What changed for you

Three things. None require any change on your side.

Lower latency. Cloudflare's edge serves your request from the nearest of 300+ data centers worldwide, instead of a single region in us-west-2. If you're in Asia or Europe, the round trip is shorter.

Independent of the failure mode that hit us today. A future incident at the same upstream cloud provider won't take Kyma down with it. We still depend on Cloudflare and on Supabase, but those are different vendors with different failure profiles. We've also kept Railway up as a documented fallback, with a runbook for flipping back in five minutes if the edge has its own bad day.

Your API and SDK stay identical. kymaapi.com/v1/chat/completions is still the URL. Your API key still works. Your usage and balance still show up in the dashboard. The OpenAI-compatible shape is unchanged, the Anthropic /v1/messages shape is unchanged, and the streaming format is byte-for-byte the same. We invested a lot of care in shape parity because anything else would have been a worse outage than the original one.

What we learned

A few honest ones.

One vendor is one single point of failure, even when the rest of the stack is diversified. Kyma was running with multiple LLM providers, multiple regions for cache, and a globally-distributed CDN. None of that protected us when the backend host went down. The lesson isn't "always have a second host". The lesson is "find every single-vendor dependency, then assume it will fail on a Tuesday afternoon".

Customers feel response shape, not just status codes. After the flip, our manual QA found five separate places where the Workers responses returned the same data as Railway but in slightly different field names. The dashboard rendered $0.00 for total spend, $0.000 for each API key's usage, and Failed to load on the rate-limits page. None of it was a backend bug per se. All of it was a customer-facing bug. We're adding CI parity tests for the next round.

Observability has to survive the thing it's watching. The daily provider-balance alert workflow had been failing every day for the last week, because it depended on secrets that were missing. We only noticed because we needed those same secrets for the incident response. If your alerting depends on the thing that's broken, it isn't alerting.

What's next

A few commitments, in priority order:

  • A CI parity test that diffs Workers responses against Railway for every ported endpoint. The next time a field renames itself, the build fails before the user sees a $0.
  • Rate-limit middleware on Workers, so burst traffic gets throttled the same way it would on Railway.
  • A pricing-table guard that fails the build if Workers and Railway start charging different cost for the same model.
  • Frontend error tracking, so we see the JS-side failures the backend logs can't see.
  • A real decision on whether Railway stays as warm standby long-term, or whether we retire it. We won't make that decision tired.

Thank you

If you tried Kyma during the outage and saw 404s, sorry. You deserved better. The team that built this is small and the incident response is now documented so the next one doesn't take 4 hours of guessing.

If you want to try the edge version, the base URL is unchanged: https://kymaapi.com/v1. Grab a Kyma key if you don't have one; signup includes $0.50 of free credit, plenty to try a few models.

Links