Skip to main content
GASSTUDI
Systems & Scale5 min read

From Local State to Real Infrastructure: The Decisions That Actually Matter

Lessons on choosing real backend infrastructure over simple local storage patterns, learned the hard way while building REFORGE.

Nic DeMore

Nic DeMore

Founder, GAS Studio · August 11, 2026

Server racks and database infrastructure in a clean data center

REFORGE started the way a lot of early builds do: state that lived locally, on the device, simple to build and fast to iterate on. For a habit and performance tracking app, that's a reasonable place to start. It's also a decision that comes with a bill attached, and the bill arrives exactly when you least want it to, right when real users start depending on the thing working consistently.

Why local state feels right at first

Early on, local storage patterns are genuinely the right tradeoff. They're fast to build, they don't require standing up backend infrastructure before you know if the product idea even holds up, and they let you validate the actual experience, does tracking a habit or a workout this way feel good to use, before investing in the plumbing underneath it.

The mistake isn't starting there. The mistake is not recognizing the moment when the tradeoff flips, when the convenience of local state starts costing more than it saves.

Where it broke down

For REFORGE specifically, the cracks showed up around anything that needed to persist reliably across sessions, sync across a device change, or survive something going wrong without losing a user's actual progress. Local state that lives only on one device is fragile in exactly the ways users notice immediately and forgive slowly. Lose someone's tracked history once, and the trust cost is disproportionate to how small the technical bug might have looked from the inside.

That's the moment it became clear that a proper database and real backend infrastructure weren't a nice-to-have for scaling later. They were a correctness requirement that had already arrived, just not one I'd fully accounted for in the original build plan.

The decision that actually mattered

The real decision wasn't "should we use a database," that part was obvious in retrospect. The real decision was recognizing that the migration would cost more the longer it waited, because more of the product's logic would end up quietly coupled to the assumption that state lives locally and simply. Every week spent building new features on top of the old assumption meant more to unwind later.

Moving to real backend infrastructure meant rethinking how data flows through the app, not just relocating where it's stored. Reliability, sync behavior, and what happens when something fails partway through all needed real answers, answers that a local-only pattern had let me avoid thinking about clearly.

What I'd do differently

I'd draw the line earlier. Local state is a fine place to start for validating an idea, but the trigger for moving to real infrastructure shouldn't be "when it breaks." It should be the moment the product is asking users to trust it with something they'd be upset to lose, streaks, history, progress that represents real effort. That's a correctness threshold, not a scale threshold, and it usually arrives well before you'd expect it to based on user count alone.

The broader principle carries past REFORGE. Simple local patterns are a legitimate way to move fast early. Just don't confuse "this is fast to build" with "this is fine to keep," and don't wait for a visible failure to make the call. By the time it's visible, it's already cost someone something real.

The migration itself was the real lesson

Actually making the move from local state to a proper backend taught me more than the decision to move did. It's not a simple lift-and-shift. Every piece of logic that had quietly assumed synchronous, always-available local data had to be rewritten to handle the reality of a network call that can be slow, can fail partway, and can return stale data if you're not careful about how you invalidate it. None of that complexity is optional once real infrastructure is involved. It's the cost of the reliability you're buying, and pretending otherwise just moves the bugs from before the migration to after it.

This is where taking the time mattered more than moving fast. I could have rushed the migration to get back to feature work sooner, and the smart-sounding shortcuts, skip proper error handling on the sync path, assume the network call always succeeds, would have shown up later as exactly the kind of failure I was trying to eliminate in the first place. Doing the migration carefully took longer up front and produced something that's actually trustworthy, which was the entire point of doing it at all.

What this changed about how I evaluate new builds

Since REFORGE, I ask a different question earlier in any new build: what does this product ask a user to trust it with, and what happens if that trust gets broken by a technical shortcut. If the answer touches anything a user would be upset to lose, streaks, financial records, health data, personal history, the backend infrastructure decision gets made early and seriously, not deferred until growth forces the issue. That single question has saved me from repeating the REFORGE lesson on at least one other venture where the temptation to start simple and defer the real infrastructure decision was strong. The temptation is understandable. It's still usually wrong for anything that asks for a user's trust.

Share this entry