Back to Blogs
April 30, 2026·7 min read

Consolidating UrSalon Preview on Vercel So It Can Afford to Keep Existing

A small monthly subscription was enough to make me rethink the architecture of UrSalon Preview. The result was a Vercel-native stack that consolidated hosting, auth, database, storage, workflows, and billing into one operating model.

VercelArchitectureCost OptimizationAI ProductsNext.jsSwiftUI

The thing that pushed me to revisit UrSalon Preview was not a catastrophic infrastructure bill. It was a small recurring subscription.

That sounds minor, but small costs change how I think about personal products. If I want an app to organically host itself for years, maybe forever, then every recurring fee has to justify its place. A product does not need to be expensive to become operationally fragile. It just needs enough little subscriptions, dashboards, secrets, and manual steps that keeping it alive starts to feel heavier than the app itself.

Key takeaways

  • Cost optimization is not only about large bills. It is about making the app cheap and simple enough to keep alive indefinitely.
  • Moving UrSalon Preview toward Vercel-native integrations reduced vendor sprawl across auth, database, storage, workflows, deployment, and billing.
  • Consolidating front end and back end under one Vercel operating model made local development, production deployment, and environment management cleaner.
  • The architecture became easier to reason about because Clerk, Neon, Vercel Blob, Workflow, Analytics, and Speed Insights now sit closer to the app runtime.

The cost that made me look twice

The monthly fee I wanted to remove was not huge. That is exactly why it was useful. Big bills are obvious. Small recurring fees hide inside the cost base and quietly become part of the product whether or not they still make sense.

For UrSalon Preview, the question became simple: if this app is going to live for a long time, what is the smallest sustainable operating shape? Not the cheapest possible stack in a fragile sense, but the cleanest one. Fewer vendors. Fewer subscriptions. Fewer places where a secret can drift or a dashboard can be forgotten.

Why I wanted a Vercel-native app shape

The target architecture was Vercel-native first. The front end already belonged naturally on Vercel as a Next.js app. The next step was asking how much of the back end could move into the same operating model without making the system worse.

That led to a stack centered on Next.js 16, Vercel Functions, Vercel Workflow, Vercel Blob, Neon Postgres through the Vercel Marketplace, Clerk through the Vercel Marketplace, and Stripe integration for web purchases. The iOS app still stays native with SwiftUI and StoreKit 2, but the durable product state lives behind the same web API boundary.

  • Next.js App Router for public pages, authenticated app screens, and API routes.
  • Clerk as the identity layer for web and iOS sessions.
  • Neon Postgres and Drizzle for the durable data model.
  • Vercel Blob for private Star Photos, reference images, and generated Style-ups.
  • Vercel Workflow for generation, fulfillment, account deletion, and other multi-step flows.

What the early history shows

The earliest UrSalon commits make the migration path pretty clear. On April 8, 2026, the repository started as a monorepo with a Next.js web app and SwiftUI iOS client. The next major step, on April 9, was the Supabase to Neon, Clerk, and Vercel Blob data migration.

That same early window included the production URL cutover, Vercel deployment fixes, Clerk middleware, test coverage, and workflow hardening. In other words, this was not just swapping one database for another. It was moving the whole product into a tighter operating model.

  • Initial monorepo: web and iOS in one repository so the product architecture could be reasoned about together.
  • Data migration: Supabase data exported, mapped, and moved into Neon-backed tables.
  • Auth migration: Supabase auth replaced with Clerk for both web and iOS identity.
  • Storage migration: private Supabase buckets replaced with private Vercel Blob objects streamed through authenticated routes.
  • Deployment cutover: the production URL moved to the new Vercel project once the new stack was ready.

Why integrations matter more than the logo

The important part was not saying the app runs on Vercel. The important part was that the operational pieces now fit together. Vercel Marketplace integrations can inject environment variables into the project, Vercel deployments carry the API and frontend together, and the logs for the app live close to the functions doing the work.

That matters when you are one person maintaining a product. Every separate vendor is another billing account, another dashboard, another set of credentials, another place to debug when production behavior does not match local behavior. Consolidation does not remove complexity, but it puts more of it in one place.

The backend shape after consolidation

The current backend is built around an authenticated Next.js API surface. Users authenticate with Clerk. The browser app uses Clerk session cookies, and the iOS app sends a Clerk bearer token from the native session. The API owns Star Photo upload, generation requests, saved looks, private image reads, credit balance, purchase history, account export, and account deletion.

Durable state sits in Neon Postgres through Drizzle. The schema is intentionally product-shaped: Star Photos, saved looks, credit ledger rows, generation events, App Store transactions, and professional interest requests. Media sits in Vercel Blob, but clients do not get raw Blob URLs. Image bytes are streamed back through authenticated route handlers after ownership checks.

  • The database is the source of truth for account state, credits, purchases, and generation history.
  • Blob storage handles media, but API routes enforce access control.
  • The credit ledger is append-only so purchases, grants, quota, usage, and reversals are auditable.
  • Zod request validation keeps the API contract explicit across web and iOS clients.

The generation workflow had to be durable

AI image generation is not a single clean request in practice. The app has to reserve a free quota slot or debit a Style-up credit, stage the input images, call Gemini, persist the result, write history, and reverse the credit if a handled failure happens at the wrong point.

That is exactly the kind of flow I do not want to manage as a loose chain of try/catch blocks. Vercel Workflow gives the generation path a clearer shape: reserve, render, persist, log, and recover. For a small app, that might sound like overkill. For an app that charges credits and stores personal photos, it is the responsible default.

The iOS app still stays native

Consolidating the backend did not mean flattening the product into a web-only app. The iOS client still matters. It is SwiftUI, uses Clerk for native auth, uses StoreKit 2 for in-app purchases, compresses images before upload, and talks to the deployed web API for the rest.

That split is the right one for this product. Native where the user experience benefits from being native. Server-owned where identity, billing, media, generation, and account lifecycle need to be consistent across devices.

Small products need boring economics

The bigger lesson is that small products need boring economics. I do not want UrSalon Preview to require constant attention just to justify its infrastructure. I want the cost base to be low enough that the app can keep existing while the product finds its audience.

That is the real reason the small subscription mattered. It represented a broader question: can this product be structured so it does not need immediate scale to survive? Consolidating onto Vercel integrations was my answer. Lower recurring cost, fewer operational surfaces, and a cleaner path from local development to production.

If you are building a small AI product and trying to make the infrastructure cheap enough to keep alive, I would be interested in comparing notes.