Stop and Start Environments On-Demand: Save Cloud Costs Without Losing State
GuideSeptember 24, 202610 min read

Stop and Start Environments On-Demand: Save Cloud Costs Without Losing State

The Cost Lever Nobody Uses Because Nobody Remembers It Exists

Most teams running many non-production environments (staging clones, long-lived feature-branch environments, demo environments) eventually notice the cloud bill for "environments nobody is actively using right now" is larger than it should be. The reflexive fix is deleting things — but deletion is a one-way door: the environment's state, its configuration nuances, its database contents, all gone, and standing it back up is a full redeploy from scratch.

The actual right tool for "not in use right now, but will be again soon" is stopping, not deleting. Stopping scales an environment's compute to zero — no running pods, no compute cost — while preserving its configuration, persistent storage, and its identity (URL). Starting it back up is fast, because nothing needs to be rebuilt, only resumed.

Stop and Start in Practice

Here's both run against a live environment, back to back, to show the round trip:

Bash
1$ bns environments stop --id 5bDn8MrEgm
2
3Environment 5bDn8MrEgm scheduled to stop with EventID j3G239e4N1
4EventID 15bW1OPWGE generated stop pipeline VK7jYqJmM1
5Pipeline details: https://environments.bunnyshell.com/b/pipeline/VK7jYqJmM1
6Environment 5bDn8MrEgm successfully stopped
Bash
1$ bns environments start --id 5bDn8MrEgm
2
3Environment 5bDn8MrEgm scheduled to start with EventID WzG0MkArNg
4EventID EVJrlyd4N1 generated start pipeline 9LMxrwXaWJ
5Pipeline details: https://environments.bunnyshell.com/b/pipeline/9LMxrwXaWJ
6Environment 5bDn8MrEgm successfully started
7Name      | web
8Endpoints | https://web-jfq6ir.bunnyenv.com/

Two things worth calling out explicitly in that output. First, both operations generate real pipelines with their own IDs — this is not an instant in-memory flag flip, it's an actual orchestrated scale-down/scale-up sequence, which is why it's reliable rather than "usually works." Second — and this is the detail that makes stop/start actually useful rather than a curiosity — the endpoint after restart is byte-for-byte identical to before the stop: https://web-jfq6ir.bunnyenv.com/. Anyone with that URL bookmarked, any CI config pointed at it, any PR comment linking to it, keeps working after a stop/start cycle with zero reconfiguration.

Stop vs. Delete: Choosing the Right One

StopDelete
Compute costZeroZero
Storage/dataPreservedRemoved
URL/identityPreservedGone
ResumeFast (restart, not rebuild)Full redeploy from scratch
Right for"Pause, will resume""Permanently done with this"

The failure mode to avoid is using delete where stop was actually the right call — someone deletes a long-lived staging clone to "save cost" over a weekend, then Monday morning discovers standing it back up means a full rebuild, re-seeding a database, re-establishing whatever manual state existed. Stop exists precisely to avoid that unnecessary round trip.

The reverse mistake is subtler but also real: using stop where delete was warranted, letting stopped-but-abandoned environments accumulate. A stopped environment costs zero compute but is not literally free (storage for any persistent volumes still exists) and is not zero-maintenance (it's still an entry in bns environments list someone eventually has to reason about). If an environment is stopped and nobody has started it in months, that's usually a signal it should be deleted, not kept stopped indefinitely "just in case."

Automating Stop/Start on a Schedule

The highest-leverage version of this isn't manually remembering to stop things — it's scheduling it. A common pattern: development and staging environments stop automatically outside working hours and start automatically before the team's day begins, since there's rarely a reason to pay for idle compute overnight or over a weekend on non-production infrastructure.

A simple cron-triggered script covers this:

Bash
1#!/bin/bash
2# nightly-stop.sh — run via cron at end of business day
3for env_id in $(bns environments list --project "$PROJECT_ID" -o json | \
4    jq -r '.[] | select(.labels.autoSchedule=="business-hours") | .id'); do
5  bns environments stop --id "$env_id" --no-wait
6done
Bash
1#!/bin/bash
2# morning-start.sh — run via cron before business hours
3for env_id in $(bns environments list --project "$PROJECT_ID" -o json | \
4    jq -r '.[] | select(.labels.autoSchedule=="business-hours") | .id'); do
5  bns environments start --id "$env_id" --no-wait
6done

Filtering by a label (autoSchedule=business-hours, set explicitly via --label at creation time) rather than blanket-stopping every environment in a project matters — some environments genuinely need to stay up around the clock (a demo environment for a prospect in a different timezone, an environment someone is actively debugging late) and should opt out of the schedule explicitly rather than being caught by an indiscriminate nightly sweep.

The Actual Savings, Roughly

Compute cost scales with running time. An environment that runs 24/7 versus one that runs only during a 10-hour business day (with weekends off entirely) is running roughly 30% of the hours in a week — a meaningful reduction for anything non-production, applied automatically rather than depending on someone remembering to click stop before leaving on a Friday.

The exact savings depend on your cluster's autoscaling behavior and whether stopped workloads' nodes actually scale down (rather than sitting idle-but-provisioned) — worth confirming with your platform team that node-level autoscaling is actually configured to shrink when pods scale to zero, since the CLI-level stop is necessary but not sufficient for realizing the cost savings if the underlying node pool doesn't also scale down.

Combining This With Auto-Destroy

Stop/start and auto-destroy-on-merge (covered in Auto-Destroy After Merge) are not competing mechanisms — they apply to different environment categories. PR-triggered ephemeral environments should be destroyed on merge/close, since there's no reason for them to exist again under that identity. Longer-lived environments — primary staging environments, self-service clones a developer is actively working with across several days — are better served by stopping overnight and starting again, since they have an ongoing reason to exist that a merged PR's ephemeral copy does not.

The Cost Math, Worked Through

To make "meaningful reduction" concrete: assume a team runs 15 non-production environments (a mix of self-service staging clones and long-lived feature environments), each costing roughly $4/day to run continuously — about $1,800/month in aggregate if left running 24/7. Scheduling stop overnight and on weekends, leaving them running only during a 10-hour weekday window, reduces active hours from 168/week to 50/week — a 70% reduction, bringing that same set of environments to roughly $540/month, a savings of over $1,200/month, achieved with two small cron scripts and a labeling convention, not a infrastructure redesign. The exact percentage will vary with your team's actual working hours and how many environments genuinely need round-the-clock uptime excluded from the schedule, but the shape of the saving — cutting cost roughly in proportion to the fraction of hours an environment sits idle — holds generally.

Handling Stateful Services Across a Stop/Start Cycle

Database components and other stateful services deserve explicit attention in this pattern, since "preserved" needs to mean something specific for them, not just "the container starts fresh." When Bunnyshell stops an environment, persistent volumes backing database components are not deleted — the underlying storage (a PersistentVolumeClaim, translated to your cloud provider's block storage) remains provisioned and intact, only the compute (the pod running the database engine) is scaled to zero. On start, the same volume is reattached to a freshly-scheduled pod, and the database resumes with its data exactly as it was — this is meaningfully different from, and much faster than, the alternative of dumping and restoring a database backup on every stop/start cycle, and it's why stop/start is viable for stateful services at all rather than being restricted to purely stateless components.

One practical implication worth testing explicitly for any service with its own internal clustering or leader-election logic (a multi-node cache cluster, a message queue with replication): confirm the service actually comes back healthy after a stop/start cycle in your specific deployment, rather than assuming it will, since some clustered services handle "all nodes disappeared and came back" more gracefully than others depending on their own internal state management.

Monitoring and Alerting on Schedule Failures

A scheduled stop/start automation that silently stops running (a cron daemon that dies, a script that starts failing after an unrelated CLI upgrade changes a flag name) has an unusual failure mode worth planning for: unlike most automation failures, this one doesn't obviously break anything a developer would notice day-to-day — environments simply stop being cost-optimized, quietly reverting to running around the clock, which looks identical to "working as intended" from inside the environment itself. The practical mitigation is a lightweight monitoring check, not full observability tooling: a scheduled job that confirms the stop/start scripts actually ran in the last 24 hours (checking bns pipeline list for expected stop/start-type pipelines around the scheduled times) and alerts if they didn't, so a broken cost-control automation is caught within a day, not discovered three months later on a bill review.

Stopping via ChatOps for Ad Hoc Cases

The scheduled automation above covers the predictable, recurring case (nightly, weekly patterns). For the unpredictable case — someone heading into a two-week vacation and wanting to pause their personal staging clone without waiting for the next scheduled window, or a reviewer wrapping up a PR review session and wanting to pause its environment immediately rather than at the next scheduled stop time — the same /bns:stop ChatOps comment covered in ChatOps for QA Teams applies here too, giving anyone with appropriate PR-comment permissions the ability to invoke the exact same stop/start mechanism on demand, without needing CLI access or waiting for a schedule. The scheduled automation and the ad hoc ChatOps trigger are not competing mechanisms — they're the same underlying bns environments stop/start operation, invoked on two different cadences for two different kinds of need.

Restart Behavior for Environments With Startup Dependencies

Multi-component environments with a dependency chain (a database that a backend waits for, a backend that a frontend waits for) handle a start the same way they handle an initial deploy — respecting the same dependsOn ordering defined in bunnyshell.yaml, rather than starting every component simultaneously and hoping for the best. This means a stop/start cycle on a properly-configured multi-service environment is not more fragile than the initial deploy was; if your dependency chain is correctly specified, the restart sequencing follows it automatically. Where this is worth double-checking explicitly is an environment whose dependency chain was never fully specified in the first place — one that happened to deploy successfully the first time because of favorable timing rather than explicit ordering — since a stop/start cycle can occasionally surface a latent ordering issue that a lucky first deploy masked.

Communicating Scheduled Stops to Stakeholders

For an environment that gets clicked on by people outside engineering — a stakeholder reviewing a staged feature, a client-facing demo environment on a stop/start schedule to save cost overnight — worth explicitly communicating the schedule rather than letting someone discover it by hitting an unresponsive link at 9pm and assuming something is broken. A one-line note near the environment's link ("this demo is available weekdays 8am–8pm ET") or a brief mention in whatever channel shares the link avoids an unnecessary "is staging down?" message landing in an engineering channel for something that is working exactly as configured.

Stop/Start Frequency: How Often Is Too Often

There's a practical limit to how frequently stop/start should be cycled, worth knowing before designing an overly aggressive schedule — each cycle is a real pipeline with real orchestration overhead (scaling down cleanly, then rescheduling pods, waiting for health checks to pass again), typically tens of seconds to a couple of minutes depending on the environment's size. A schedule that stops and starts an environment many times a day (hourly, say, trying to squeeze out maximal savings) spends a meaningful fraction of that time in transition rather than either fully running or fully stopped, and accumulates more pipeline overhead than the marginal savings usually justify. A once- or twice-daily cycle (overnight, and optionally a midday pause for teams with a predictable lunch-hour lull) captures the large majority of the available savings without the diminishing-returns overhead of a much more aggressive schedule.

Making This the Default, Not the Exception

The single highest-leverage step described in this guide is turning scheduled stop/start into the default posture for non-production environments, rather than an opt-in optimization a few cost-conscious individuals remember to configure for their own environments. Labeling conventions and a shared scheduling script, applied at the primary-environment level so every derived environment inherits the same schedule automatically, turn "someone occasionally remembers to save money" into "the platform saves money by default, and specific environments opt out when they genuinely need round-the-clock uptime" — the same inversion of defaults that makes IP restriction and network isolation reliable elsewhere in this pillar.

For the full lifecycle command reference stop/start belong to, see Managing Environment Lifecycle via CLI. For the terminal-state counterpart to stopping — permanent teardown rather than a pause — see Auto-Destroy After Merge.

Checklist

  • Non-production environments that don't need 24/7 uptime are labeled and covered by a scheduled stop/start
  • Cluster-level node autoscaling is confirmed to actually shrink when workloads scale to zero, not just the pods
  • Environments needing round-the-clock uptime are explicitly excluded from the schedule, not accidentally caught by it
  • Stopped-but-unused-for-months environments are periodically reviewed for outright deletion, not left stopped indefinitely
✦✦

Cut idle-hours cloud spend without losing environment state.

14-day full-feature trial. No credit card required. Pay-as-you-go from $0.007/min per environment.

Frequently Asked Questions

What is the difference between stopping and deleting an environment?

Stopping scales the environment's compute to zero, preserving its configuration, persistent storage, and URL, so it can be resumed quickly. Deleting removes everything permanently, including storage, and the environment cannot be resumed — a new one must be created from scratch.

Does a stopped environment still cost money?

Compute cost stops accruing since workloads are scaled to zero. Persistent storage (databases, volumes) may still incur a small storage cost depending on your cloud provider's pricing, since the data itself is preserved, but this is typically far smaller than the compute cost of a running environment.

How long does it take to start a stopped environment back up?

Faster than a full deploy from scratch, since the images are already built and configuration is already applied — it is closer to a normal pod restart time (seconds to low minutes depending on app startup time) rather than a full build-and-provision cycle.

Can I schedule automatic stop/start, like stopping every environment overnight?

Yes, this is a common pattern implemented via a scheduled CI job or cron-triggered script calling bns environments stop/start on a defined schedule, since there is no reason to pay for compute on development environments outside working hours for most teams.

Does the environment keep the same URL after being stopped and started again?

Yes — confirmed directly: the same auto-generated hostname resolves correctly again immediately after a start, with no reconfiguration needed on the caller's side.