Speaking

How Spring Migrated 6.5 Million Stores Off a Rails Monolith

I joined Rick Takes on stage at a Netlify conference to walk through how Spring (formerly Teespring) went from a slow, tangled Ruby on Rails monolith to a headless Jamstack architecture — without tearing everything down at once.

March 8, 2021
7 min read
JamstackHeadless ArchitectureRuby on RailsNetlifyMicroservicesEngineering

In March 2021, I joined Rick Takes — Spring's Director of Engineering — at a Netlify conference to talk about one of the more complex technical migrations I'd been part of: moving Spring's entire e-commerce platform off a Ruby on Rails monolith.

Spring, if you're not familiar, was formerly known as Teespring — a Y Combinator-backed platform that lets creators design and sell custom products. By the time we started this migration, the platform had over 6.5 million stores and more than a million daily visitors. The scale made this migration both more necessary and more terrifying.

Watch the full talk on YouTube


The Problem with the Monolith

The Rails monolith had done its job well for years. But everything was tangled together — storefronts, checkout, shopping cart, fulfillment — all living in one repository, sharing one deployment pipeline. Bugs in one domain could ripple across everything else. Iteration cycles slowed down. Build times hit 90 minutes.

The product was growing faster than the architecture could support it.

The natural instinct in that situation is to blow it all up and start over. We decided not to.


An Iterative Approach

The core principle we built the migration around: don't tear down what's working while building what's next.

Rick put it well in the talk: "We wanted a solution that would enable us to pull apart our monolith without having to completely tear it down."

The mechanism that made this work was an API adapter pattern. Rather than ripping out the Rails backend immediately, we proxied existing Rails responses through AWS API Gateway and translated them into modern, versioned API formats. New frontend code could talk to clean APIs. The legacy backend kept running underneath, unaware anything had changed.

This let us extract domain by domain — storefronts first, then checkout, then cart — without a big-bang cutover. Each piece moved when it was ready, not all at once.


The New Stack

On the frontend, everything moved to React, deployed on Netlify's edge network. New features bypassed Rails entirely, connecting directly to microservices. The headless storefront layer went live on Netlify, giving us access to the CDN edge for performance improvements that we could see immediately in conversion data.

The numbers after the migration told the story clearly:

  • Build times dropped from 90 minutes to 1 minute
  • Branded storefronts saw measurable conversion improvements and lower mobile bounce rates
  • New partner integrations that used to take months were down to days

What I Took Away

A few things stuck with me from this project and from telling the story publicly.

The first is that iterative migration is underrated. The "rewrite everything" instinct is strong, but it's also how you end up with two half-finished systems instead of one working one. The adapter pattern gave us a graceful on-ramp.

The second is about API design. We spent real time thinking about what the clean version of our APIs should look like — not just what Rails was already returning. That investment paid off as we added microservices. Good contracts between services age much better than convenient ones.

The third is that public talks force you to actually understand what you built. Preparing for this one helped me articulate decisions we'd made somewhat organically during the build. Recommended.


You can read the full case study on Netlify's blog, and watch the full talk on YouTube.

Thank you for reading. If you enjoyed this essay, please share it with others who might find it valuable.

Read more essays