Live Nov 18 · Cohort 3Nov 18, 19:00 MSK — free hands-on AI agents live workshop · Live Cohort 3 starts Nov 23Join Nov 18 Live →Cohort 3 (Nov 23)
ReleaseAPI / Product · ActionableLovable Blog→ original

Lovable moves updates to its own server and cuts data volume by roughly 97%

Lovable removed direct browser subscriptions to Firestore: they transmitted entire documents and required access rights to be maintained separately in the database and the API. Now a Go service checks permissions itself, assembles the response and sends changes over WebSocket. For example, once access is revoked, a member stops receiving project updates right in an open tab. By the team's estimate, the volume of transmitted data fell by roughly 97% compared with full responses.

AI-processed from Lovable Blog; edited by Hamidun News
Lovable moves updates to its own server and cuts data volume by roughly 97%
Source: Lovable Blog. Collage: Hamidun News.
Listen to article
Article Fact Sheet & Key Figures
ParameterDetails
Primary sourceLovable Blog ↗
Editor-in-Chief
Key metric #1At peak the service handled 2.06 million concurrent subscriptions.
Key metric #2Permission checks are recomputed when fields relevant to access change.
Key metric #3Before switching users over, the service was tested on shadow traffic.

Add an internal field to a project document, and the user's browser can already receive it. Lovable faced this risk while its frontend subscribed directly to Firestore documents. Developers had to think about the public API even when making an ordinary change to the database structure. And access rights had to be kept consistent in two places: the Firestore rules and the server-side Go code.

The team moved updates to its own service, Lovable Realtime. Now the server decides which fields to send to a particular user and revisits that decision whenever data or permissions change. According to Lovable, the service withstood a peak of 2.06 million concurrent subscriptions. The practical interest here lies in how the subscriptions are built, how permissions are checked, and how a live product was migrated.

What happens after access is revoked

Imagine a company workspace. An employee opened a project, then an administrator removed them from the group with access. The already open tab must stop receiving updates. When the set of permissions changes, the server may also need to remove individual fields from subsequent responses.

At Lovable, the access check was made a tracked data source just like the project itself. A subscription depends on both the project's contents and the user's permissions. A change in either dependency makes the server recompute the result available to the user. When access is revoked, the stream must close in the middle of a session.

This proved especially useful for enterprise groups: the necessary information lived in different databases, Firestore and Spanner. Firestore security rules could not read Spanner. A custom server layer made it possible to combine data from both databases in one response and apply the API's shared permission system.

However, this approach has a cost. At first, any change to a project document triggered a full permission recalculation, including ordinary file edits. The team kept recalculation only for changes to fields involved in the access decision. According to the team, the number of recalculations fell by roughly 84%. The list of such fields has to be maintained as part of the authorization logic; a separate static check helps find omissions in the packages it covers.

How updates reach the browser

Each tab gets one WebSocket connection, inside which several subscriptions run. Changes in Firestore and Spanner arrive through a change-capture mechanism at a bridge, then in NATS. The Go service receives the event and recomputes the affected subscriptions.

Next, it compares the hash of the new result with the previous one. If nothing changed for the user, there is nothing to send. If something did change, only the difference can be transmitted. Several interface components with the same subscription automatically share a single server-side subscription.

On reconnection, the browser sends a fingerprint of its saved state. The server rechecks permissions and loads current data. If the result matches, it confirms that the cache can be used without retransmitting the entire contents.

Over the 30 days covered in the article, the service delivered 2.61 billion frames of data and changes. The team estimated that hypothetically sending every computed result in full would have amounted to 40 TB. The volume actually transmitted was 1.11 TB, thanks to suppressing duplicates, sending diffs, and reusing state on reconnection. Hence the estimated reduction of roughly 97%. This is a comparison against a calculated baseline of full responses, not a measured reduction in Firestore costs.

What to take into your own product

The switchover began in shadow mode: the browser subscribed to the new service but kept displaying data from Firestore. This is how the team discovered waves of reconnections after deployments, failure classification errors, and a response size limit that was too small. The share of users was then increased in steps. According to Lovable, the migration went through without user-facing incidents.

One more detail matters for operations: adding servers does not offload long-lived connections that are already established. That is why Lovable limits the number of connections per service instance, keeps a memory reserve, and spreads out reconnections after a deployment over time.

Far from every team will need to build such a system from scratch. Here the choice was shaped by existing databases, a Go backend, and the requirement to change permissions during a session. But you can check your own product right now: which fields go to the browser, what happens after access is revoked, and whether the server withstands many tabs returning at once.

Story

Key Questions Answered

What happens after access is revoked?

Imagine a company workspace. An employee opened a project, then an administrator removed them from the group with access. The already open tab must stop receiving updates. When the set of permissions changes, the server may also need to remove individual fields from subsequent responses. At Lovable, the access check was made a tracked data source just like the project itself. A subscription depends on both the project's contents and the user's permissions.

How updates reach the browser?

Each tab gets one WebSocket connection, inside which several subscriptions run. Changes in Firestore and Spanner arrive through a change-capture mechanism at a bridge, then in NATS. The Go service receives the event and recomputes the affected subscriptions. Next, it compares the hash of the new result with the previous one. If nothing changed for the user, there is nothing to send. If something did change, only the difference can be transmitted.

What to take into your own product?

The switchover began in shadow mode: the browser subscribed to the new service but kept displaying data from Firestore. This is how the team discovered waves of reconnections after deployments, failure classification errors, and a response size limit that was too small. The share of users was then increased in steps. According to Lovable, the migration went through without user-facing incidents.

ZK
Zhemal Khamidun — CPO at Alpina Digital, product manager of AlpinaGPT. Building AI products since 2019. Hamidun News is a pet project that grew into a production aggregator with 6,000+ readers.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
What do you think?
Loading comments…