Blog

The scratch org tax — what org setup really costs, and which parts you can stop paying

Scratch orgs solved a real problem: disposable, source-driven environments instead of a shared sandbox everyone tramples. But "disposable" cuts both ways — every org you throw away is one you rebuilt first. Here's the full lifecycle, priced honestly.

Short version

A scratch org is create + deploy + permission sets + seed data, repeated every time one expires or breaks — plus Dev Hub allocations that make orgs a rationed resource on larger teams. Script all of it, keep the definition file lean, and notice which parts of your day actually need the org: UI work and integration checks do; the write-test-run loop on Apex doesn't, and it's the loop you run a hundred times a day.

The lifecycle, with the real commands

Nobody's scratch org setup is one command. The honest minimum is four:

bash
# 1. Create (the definition file decides features, settings, edition)
sf org create scratch --definition-file config/project-scratch-def.json \
  --alias dev --duration-days 7 --set-default

# 2. Deploy your source
sf project deploy start

# 3. Assign permission sets
sf org assign permset --name Invoicing_Admin

# 4. Seed the data your app assumes exists
sf data import tree --plan data/seed-plan.json

Step 1 alone takes a few minutes when the pool is warm and noticeably longer when it isn't. Steps 2–4 are where real projects diverge: a mature org has permission sets that depend on features, features that need activation settings in the definition file, and seed data with lookup relationships that sf data import tree can only handle if you've structured the plan files just so. Most teams end up with a setup.sh that grows a new workaround every quarter.

Expiry is a feature that bills you weekly

Scratch orgs live 1–30 days, 7 by default. Expiry is what makes them disposable — and it also means the setup above isn't a one-time cost, it's a subscription paid in developer mornings. The Monday ritual of "my org expired, give me 20 minutes" is so normal on Salesforce teams that nobody prices it anymore: for a team of five rebuilding weekly, that's roughly two developer-days a month spent reconstructing environments that existed on Friday.

Dev Hub allocations add a ceiling: your edition caps both active scratch orgs and daily creations. On a big team, orgs become a resource you manage — someone keeps a spreadsheet, someone hoards a long-lived org "just in case," and the disposability that justified the model quietly erodes.

Keeping the tax low

  • Script the whole lifecycle, not just creation. One command from nothing to ready-to-work, checked into the repo, maintained like code — because it is code.
  • Keep the definition file minimal. Every feature flag you add is another thing that can fail on create day. Add features when code needs them, not defensively.
  • Use snapshots if your edition has them. Scratch org snapshots capture a configured org and replay it faster than rebuilding from source.
  • Don't let seed data live only in someone's head. sf data export tree from a configured org gets it into version control.

The sharper question: which parts need an org at all?

Everything above optimizes the rebuild. The bigger win is noticing what you rebuilt it for. Look at an Apex developer's actual day: the overwhelming majority of org interactions are the same loop — save a class, run its tests, read the failure, repeat. That loop uses the org as an Apex runtime and nothing else. No UI, no integration, no declarative metadata under test.

That's the part Nimbus takes off the org entirely. It runs your Apex tests locally against your source tree — parser, interpreter, SOQL against an embedded PostgreSQL, triggers firing on DML, @testSetup and test isolation behaving the way the platform does. No creation step, no deploy, no expiry:

bash
# No org anywhere in this loop
nimbus test "InvoiceServiceTest.*"

# Watch mode: tests re-run on save
nimbus watch

A local environment can't expire on Monday and doesn't count against anyone's allocation. Test data is created the same way it is in org tests — in Apex, by your factory classes — so there's no seed-plan equivalent to maintain for the test loop.

Scratch orgs remain the right tool for what they're genuinely for: Lightning pages, Flows you're clicking through, permission checks, anything a human looks at. The division of labor that works is org-shaped work in orgs, code-shaped work on your machine — a full comparison is at Nimbus vs. scratch orgs.

Checklist

  • One script from zero to working org, in the repo, maintained.
  • Lean definition file — features on demand, not by default.
  • Seed data in version control via sf data export tree.
  • Count your weekly rebuild cost — most teams have never measured it.
  • Move the Apex test loop local — it's the highest-frequency org use and the easiest to take off the org.

The test loop, without the org

Nimbus runs your Apex tests against your working tree on an embedded PostgreSQL — no scratch org, no sandbox, no Docker, nothing to expire.