Back to blog

May 11, 2026

Preview Deployments Weren't Built for This

Why preview URLs are excellent for frontends but often fall apart for multi-service apps, and why a shared local stack is often the better review workflow.

Preview Deployments Weren't Built for This

Preview deployments are one of the best ideas in modern dev tooling. Push a branch, get a URL, share it. Vercel, Netlify, Cloudflare Pages — they all do it beautifully.

For frontends.

The moment your app is more than a frontend, preview deployments start falling apart. And nobody talks about it because the landing pages make it look so seamless.


The Frontend Illusion

Preview deployments were designed for static sites and serverless functions. They excel at this. Push a Next.js app with API routes, get a working preview. It's magic.

But most real apps aren't self-contained in one framework. You've got a React frontend that talks to a separate Express API. Or a Next.js frontend that depends on a Python ML service. Or a full-stack app with a database, a queue worker, and a websocket server.

Preview deployments don't spin up your API. They don't run your database. They don't start your background workers. They deploy the frontend and hope for the best.

So your preview URL loads a beautiful UI that immediately breaks because the API it depends on doesn't exist in that environment. The login form submits to nowhere. The dashboard shows a loading spinner forever. The real-time features silently fail.

You've shared a facade, not your app.


The Environment Gap

Even when you manage to wire up a backend to your preview deployment — through staging APIs, shared dev databases, or container-based preview environments — you're now maintaining infrastructure just to show someone your work.

That means:

Environment variables. Your preview needs a separate set. Database URLs, API keys, third-party credentials — all different from local, all needing to be configured and kept in sync.

Data. Your preview database needs seed data that makes the app look real. Empty dashboards don't demo well. Stale data from last month's preview doesn't either.

Auth. Your preview needs working authentication. If it shares a database with staging, you need test accounts. If it doesn't, you need to set up auth from scratch for a throwaway URL.

Services. Every microservice, background job, and third-party integration needs to work in the preview environment. If any of them doesn't, the preview is a partial demo at best.

This is a lot of work for a URL that exists to answer the question "does this look right?"


What You're Actually Trying to Do

Step back. Why do you create a preview deployment?

Usually one of these: you want a teammate to review your changes. You want a client to see progress. You want to test something on a real URL before merging. You want someone non-technical to click through the app.

In every case, the goal is the same: let someone else use the app and find out what happens.

You don't need a deployed environment for that. You need a shared URL to your running app.


The DemoTape Alternative

DemoTape skips the deployment entirely. Your app runs locally — all of it. Frontend, backend, database, workers, everything. The full stack, exactly as it runs on your machine.

npx @demotape.dev/cli gives you a shareable URL that routes to all your local services behind a single origin. No deploying. No environment config. No seed data. No broken previews where the frontend loads but the API doesn't exist.

Your reviewer gets the real app, not a partial deployment of it.

But here's the part that matters more: DemoTape records the session. Every click, scroll, console error, and failed request. When your teammate or client finishes reviewing, you don't get a Slack message saying "looks good" or a GitHub comment that says "LGTM." You get a full replay of what they actually did.

That's the difference. Preview deployments give you a URL. DemoTape gives you a URL and the data about what happened when someone used it.


Preview Deployments Miss the Feedback

Even when preview deployments work perfectly — frontend renders, API connects, data loads — they still have a fundamental gap: you have no idea what the reviewer experienced.

They opened the URL. They clicked around. They closed the tab. Maybe they left a comment on the PR: "looks good." Maybe they didn't.

You don't know if they tested the happy path or the edge case. You don't know if they saw the error state you specifically wanted feedback on. You don't know if they spent 30 seconds or 5 minutes. You don't know if they hit a bug and didn't mention it because they assumed it was a known issue.

Preview deployments treat sharing as the end of the workflow. Here's the URL, good luck.

DemoTape treats sharing as the beginning. Here's the URL — and when they're done, here's everything that happened.


When to Use What

Preview deployments are still great for what they were designed for: deploying frontends to shareable URLs, running automated tests against real environments, and integration checks in CI pipelines.

But if you're trying to get feedback on a multi-service app that isn't fully deployable in a preview environment — which is most real apps — you're fighting the tool instead of using it.

DemoTape is for the earlier, rougher stage. The "it runs on my machine, I need someone else to try it" stage. The stage where deploying is overkill, sharing is the goal, and knowing what happened during the session is the actual value.


Extract More From Every Review

You only get so many people to look at your work. Teammates are busy. Clients are distracted. Design reviewers have fifteen other things open. Every session where someone uses your app is scarce and valuable.

Preview deployments waste that attention — you get a URL visit with no data. DemoTape captures it: the full session, the errors, the hesitations, the exact moment they got confused or gave up.

Stop deploying previews that show half your app and tell you nothing about what happened. Share the real thing and watch the replay.

npx @demotape.dev/cli — your full app, one URL, every session recorded.