Journal
Engineering3 min read

A seeded sandbox beats a copy of production

Our whole local environment is an in-process Postgres that boots from empty, applies real migrations, and fills itself with a convincing fake salon. No production credentials on laptops, no real client data in screenshots, and a demo that never goes stale.

BEThe Bookatu engineering team

There is a moment in every small team's life when someone suggests pointing local development at a copy of the production database, because the fake data feels thin and the real bugs only happen with real records. It is a tempting idea with a long tail of regret: credentials spread across laptops, client names in screenshots, a test email job that one day finds real addresses. We went the other way and never looked back.

An entire Postgres inside the process

Embedded Postgres builds have gotten genuinely good. Our app decides at startup: if real database credentials exist in the environment, use the hosted database; if they are blank, spin up an in-process Postgres that lives in a local folder. Development machines simply never have the credentials, so the failure mode of a misconfigured laptop is a fresh empty database, not a production incident.

js
// Choose the database at runtime. Blank env = embedded, local, harmless.function makeDb() {  const url = process.env.DATABASE_URL;  if (url) return connectHosted(url);  // In-process Postgres persisted to a local folder  const client = new EmbeddedPostgres('./.pgdata');  return drizzle(client, { schema });}

The rebuild path matters as much as the engine. We recreate the local database by applying the same migration files that production ran, in order, from the first one. That single decision has caught a family of bugs for free: a migration that assumed a column from a later file, a schema change that worked against a stale snapshot but not from scratch. If the laptop cannot build the schema from history, the next deploy could not either.

Seed a business, not rows

The difference between useless and useful fake data is narrative. Our seed script does not insert ten users named test. It creates a salon with a name, staff with specialties, services with honest prices and durations, clients with visit histories, upcoming appointments, retail products with stock levels and a ledger behind them. The pages look inhabited, which means layout bugs, empty states, and awkward truncation show up the way they would for a real customer.

A booking dashboard filled with seeded example data: revenue, appointments and client activity
Everything in this screenshot is fiction. That is exactly what makes it publishable.

That last property is easy to underrate. Every screenshot in our docs, our blog, and our bug reports comes from the seeded sandbox. Nobody has to squint at an image asking whether a client name slipped through, because there are no client names to slip. The safest redaction process is having nothing to redact.

What to get right

  • Make the safe path the default path. Developers should have to go out of their way to reach real data, not out of their way to avoid it.
  • Neutralize side effects too: email, payments and storage keys stay blank locally, so a loop over seeded clients can never message a real person.
  • Seed the states you dread: the brand-new account, the fully booked day, the out-of-stock product, the client with one visit years ago.
  • Keep the seed in code review. When a feature adds a table, the seed grows with it, or the sandbox quietly rots.

The payoff compounds. New teammates run two commands and have a working business to poke at. Visual QA can photograph every page without a privacy review. And the demo environment is always five minutes from pristine, because pristine is just a rebuild away.

Production data answers questions. Seeded data lets you ask them safely.

local development environmentseed dataembedded postgrestest data privacydeveloper experience
Ready to put this to work?

Bookatu gives you a branded booking page, deposits, memberships, gift cards and reminders, with 0% commission on your bookings.

Start free