You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 8b99bc3
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: src/content/articles/ephemeral-preview-environments-cost-control-cleanup/index.mdx
+26-16Lines changed: 26 additions & 16 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -15,7 +15,7 @@ import sharedVsDedicatedDiagram from "./diagrams/shared-vs-dedicated-resource-co
15
15
*[TTL]: Time To Live
16
16
*[RDS]: Relational Database Service
17
17
18
-
Preview environments for every PR sound like a developer experience win until someone notices the cloud bill. I've seen this pattern play out multiple times: a team enables preview deployments, developers love the fast feedback loops, and six weeks later finance is asking why infrastructure costs tripled.
18
+
<Highlighter>Preview environments for every PR sound like a developer experience win until someone notices the cloud bill.</Highlighter> I've seen this pattern play out multiple times: a team enables preview deployments, developers love the fast feedback loops, and six weeks later finance is asking why infrastructure costs tripled.
19
19
20
20
The math is straightforward but easy to ignore. A 50-developer team with an average of 40 open PRs, each spawning a full stack with database, Redis, and object storage, is running 40 duplicate environments around the clock. Most sit idle — the PR author pushed code, tested for an hour, then moved on. But the database is still running. The load balancer is still running. The persistent volumes are still allocated.
21
21
@@ -32,7 +32,12 @@ A good TTL policy has three layers. First, a hard maximum lifetime — environme
32
32
The defaults should be aggressive. A 72-hour maximum lifetime and an 8-hour idle timeout cover the vast majority of legitimate use cases. PRs that need longer — demo environments, long-running feature branches — can request an extension via a label or approval workflow.
33
33
34
34
<Table
35
-
variant="vertical-column-delineation-table"
35
+
variant="grid-and-accent-header-table"
36
+
fullWidth={false}
37
+
classes={{
38
+
figure: "mt-8 mb-8",
39
+
tbody: '!text-content',
40
+
}}
36
41
content={{
37
42
figure: "TTL policy tiers for different use cases.",
@@ -93,6 +98,7 @@ The most impactful cost optimization is using shared infrastructure with logical
93
98
94
99
<Diagram
95
100
src={sharedVsDedicatedDiagram}
101
+
magnifyButtonPosition="top-left"
96
102
title="Shared vs dedicated resource cost comparison."
97
103
description="Flowchart comparing dedicated preview databases with a shared database model. In the Dedicated (Expensive) group are three separate databases labeled PR-123 DB, PR-124 DB, and PR-125 DB. In the Shared (Cost-Effective) group, one Shared DB branches into three isolated schemas: schema_pr_123, schema_pr_124, and schema_pr_125. A third group labeled Cost Comparison (db.t3.small) shows that three dedicated databases cost 3 x $30/mo = $90/mo, while one shared database costs 1 x $30/mo = $30/mo. Dotted arrows connect the dedicated databases to the higher cost and the shared database to the lower cost. The diagram demonstrates that logical isolation within a shared service can preserve separation while dramatically lowering per-preview infrastructure cost."
98
104
/>
@@ -116,23 +122,24 @@ Deleting an environment when its TTL expires works, but sometimes you want a mid
116
122
Hibernation works well for environments that are idle but might be needed again. A developer working on a feature for two weeks doesn't want their environment destroyed every night — they want it to stop costing money overnight and wake up when they need it.
117
123
118
124
<Table
119
-
variant="vertical-column-delineation-table"
125
+
variant="criteria-highlight-table"
126
+
fullWidth={false}
120
127
content={{
121
128
figure: "Hibernation triggers and their cost impact.",
@@ -143,30 +150,33 @@ Note the difference from TTL idle timeout: hibernation kicks in earlier (4 hours
143
150
144
151
The best hibernation UX is transparent to developers. When someone visits a hibernated environment URL, the system automatically wakes it. Show a loading page while resources start up, then redirect to the now-running environment. KEDA (Kubernetes Event-Driven Autoscaling) provides the scaling primitives — it can scale deployments to zero based on custom metrics (like HTTP request rate), then scale back up when traffic arrives. Custom ingress annotations or a lightweight proxy can intercept the initial request and trigger the wake.
145
152
146
-
The tradeoff is cold start time. Waking a hibernated environment takes 30-60 seconds for Kubernetes deployments to scale up, longer if databases need to start. For environments with dedicated RDS instances, AWS allows you to stop the instance (saving compute costs) while retaining storage — starting it again takes a few minutes. The inverse also applies: the loading page should be informative about this tradeoff. Explain that the environment was hibernated to save costs, show the PR number, and indicate expected wake time. Auto-refresh every few seconds so developers don't have to manually reload.
147
-
148
153
<Callout type="success">
149
154
Hibernation with wake-on-access gives you the best of both worlds: environments are always "available" from the developer's perspective, but only incur costs when actively used. A 4-hour idle timeout with scheduled nights/weekends hibernation can reduce preview environment costs by 60%+.
150
155
</Callout>
151
156
157
+
The tradeoff is cold start time. Waking a hibernated environment takes 30-60 seconds for Kubernetes deployments to scale up, longer if databases need to start. For environments with dedicated RDS instances, AWS allows you to stop the instance (saving compute costs) while retaining storage — starting it again takes a few minutes. The inverse also applies: the loading page should be informative about this tradeoff. Explain that the environment was hibernated to save costs, show the PR number, and indicate expected wake time. Auto-refresh every few seconds so developers don't have to manually reload.
158
+
152
159
## Putting It Together
153
160
154
161
These three strategies address the biggest cost drivers without requiring complex tooling:
0 commit comments