Hex Cost Tuning
Overview
Hex pricing combines per-seat licensing with compute-based charges for notebook runs and data connections. Each scheduled or ad-hoc notebook execution consumes compute credits proportional to query complexity and data volume processed. Organizations running dozens of notebooks on hourly schedules — many producing identical results from unchanged data — accumulate unnecessary compute costs. Caching run results, optimizing schedules, and consolidating redundant notebooks are the highest-leverage cost reduction strategies.
Cost Breakdown
| Component |
Cost Driver |
Optimization |
| Seat licenses |
Per-user/month (Team: $28/user) |
Audit active editors quarterly; move viewers to free tier |
| Notebook runs |
Compute per scheduled or manual execution |
Cache results for unchanged data; extend run intervals |
| Data connections |
Active warehouse/database connections |
Consolidate overlapping connections; remove unused ones |
| Scheduled runs |
Cron-triggered executions across all projects |
Audit schedules — reduce frequency for stable data |
| API calls |
Admin and Run API requests |
Batch API operations; use cached results endpoint |
API Call Reduction
class HexRunOptimizer {
private resultCache = new Map<string, { data: any; timestamp: number }>();
private dataHashes = new Map<string, string>();
async runIfChanged(projectId: string, runFn: () => Promise<any>): Promise<any> {
const currentHash = await this.getSourceDataHash(projectId);
if (this.dataHashes.get(projectId) === currentHash) {
const cached = this.resultCache.get(projectId);
if (cached) return cached.data; // Source unchanged — serve cached result
}
const result = await runFn();
this.resultCache.set(projectId, { data: result, timestamp: Date.now() });
this.dataHashes.set(projectId, currentHash);
return result;
}
private async getSourceDataHash(projectId: string): Promise<string> {
const res = await fetch(`/api/v1/project/${projectId}/status`);
return (await res.json()).sourceDataHash;
}
}
Usage Monitoring
class HexCostMonitor {
private runs = new Map<string, number[]>();
private weeklyBudget = 500; // max runs per week
recordRun(projectId: string): void {
const timestamps = this.runs.get(projectId) || [];
timestamps.push(Date.now());
this.runs.set(projectId, timestamps);
}
getWeeklyReport(): { totalRuns: number; byProject: Record<string, number> } {
const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
const byProject: Record<string, number> = {};
let total = 0;
for (const [id, stamps] of this.runs) {
const count = stamps.filter(t => t > weekAgo).length;
byProject[id] = count;
total += count;
}
return { totalRuns: total, byProject };
}
}
Cost Optimization Checklist
Error Handling
| Issue |
Cause |
Fix |
| Compute costs spiking |
Hourly schedules on notebooks with daily-changing data |
Extend schedule to match data refresh cadence |
| Stale cached results |
Source data changed but cache not invalidated |
Use source data hash comparison before serving cache |
| API rate limit (429) |
Too many concurrent run triggers |
Queue runs with concurrency limit of 3 |
| Unused notebooks accruing runs |
Abandoned projects still on schedule |
Audit and disable schedules for inactive projects |
| Connection pool exhausted |
Too many simultaneous data source queries |
Consolidate connections; stagger scheduled run times |
Prerequisites
- An approved budget, baseline run/compute metrics, safe sandbox project, and named owner for each execution path.
- A dry-run plan and rollback revision for schedule, cache, concurrency, and project parameters.
Instructions
- Measure aggregate run frequency, duration band, retries, cache behavior, and failure rate before proposing a control.
- Classify candidates as duplicate, expired, nonessential, or owner-review without inspecting or exporting workspace data.
- Dry-run the control, compare aggregate cost/run counts and safe project assertions, then canary one project.
- Promote only with owner approval; roll back for changed output shape, access scope, freshness, or increased failures.
- Keep a reversible revision and state savings as a range rather than an unsupported guarantee.
Output
Return a cost-change receipt with baseline/projected runs, control revision, owner approval, canary result, aggregate assertions, estimated savings range, and rollback reference. Exclude SQL, output, and credentials.
Examples
project=proj-sandbox-12; baseline_runs=12000; deferred=120; deduped=900; assertions=pass; rollback=cost-r18 is a safe cost decision.
Resources
Next Steps
See hex-performance-tuning.
1---2name: hex-cost-tuning3description: Optimize Hex costs through tier selection, sampling, and usage monitoring. Use when analyzing Hex billing, reducing API costs, or implementing usage monitoring and budget alerts. Trigger with phrases like "hex cost", "hex billing", "reduce hex costs", "hex pricing", "hex expensive", "hex budget".4license: MIT5---6# Hex Cost Tuning
7
8## Overview
9
10Hex pricing combines per-seat licensing with compute-based charges for notebook runs and data connections. Each scheduled or ad-hoc notebook execution consumes compute credits proportional to query complexity and data volume processed. Organizations running dozens of notebooks on hourly schedules — many producing identical results from unchanged data — accumulate unnecessary compute costs. Caching run results, optimizing schedules, and consolidating redundant notebooks are the highest-leverage cost reduction strategies.
11
12## Cost Breakdown
13
14| Component | Cost Driver | Optimization |
15|-----------|------------|--------------|
16| Seat licenses | Per-user/month (Team: $28/user) | Audit active editors quarterly; move viewers to free tier |
17| Notebook runs | Compute per scheduled or manual execution | Cache results for unchanged data; extend run intervals |
18| Data connections | Active warehouse/database connections | Consolidate overlapping connections; remove unused ones |
19| Scheduled runs | Cron-triggered executions across all projects | Audit schedules — reduce frequency for stable data |
20| API calls | Admin and Run API requests | Batch API operations; use cached results endpoint |
21
22## API Call Reduction
23
24```typescript
25class HexRunOptimizer {
26 private resultCache = new Map<string, { data: any; timestamp: number }>();
27 private dataHashes = new Map<string, string>();
28
29 async runIfChanged(projectId: string, runFn: () => Promise<any>): Promise<any> {
30 const currentHash = await this.getSourceDataHash(projectId);
31 if (this.dataHashes.get(projectId) === currentHash) {
32 const cached = this.resultCache.get(projectId);
33 if (cached) return cached.data; // Source unchanged — serve cached result
34 }
35 const result = await runFn();
36 this.resultCache.set(projectId, { data: result, timestamp: Date.now() });
37 this.dataHashes.set(projectId, currentHash);
38 return result;
39 }
40
41 private async getSourceDataHash(projectId: string): Promise<string> {
42 const res = await fetch(`/api/v1/project/${projectId}/status`);
43 return (await res.json()).sourceDataHash;
44 }
45}
46```
47
48## Usage Monitoring
49
50```typescript
51class HexCostMonitor {
52 private runs = new Map<string, number[]>();
53 private weeklyBudget = 500; // max runs per week
54
55 recordRun(projectId: string): void {
56 const timestamps = this.runs.get(projectId) || [];
57 timestamps.push(Date.now());
58 this.runs.set(projectId, timestamps);
59 }
60
61 getWeeklyReport(): { totalRuns: number; byProject: Record<string, number> } {
62 const weekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
63 const byProject: Record<string, number> = {};
64 let total = 0;
65 for (const [id, stamps] of this.runs) {
66 const count = stamps.filter(t => t > weekAgo).length;
67 byProject[id] = count;
68 total += count;
69 }
70 return { totalRuns: total, byProject };
71 }
72}
73```
74
75## Cost Optimization Checklist
76
77- [ ] Cache notebook results with `updateCacheResult: true`
78- [ ] Skip re-runs when source data is unchanged
79- [ ] Audit scheduled run frequencies — extend intervals for stable data
80- [ ] Move read-only users from Team to free viewer tier
81- [ ] Consolidate duplicate notebooks querying the same data
82- [ ] Remove unused data connections
83- [ ] Set weekly run budget alerts at 80% threshold
84- [ ] Identify overrun projects (>20 runs/week) for schedule review
85
86## Error Handling
87
88| Issue | Cause | Fix |
89|-------|-------|-----|
90| Compute costs spiking | Hourly schedules on notebooks with daily-changing data | Extend schedule to match data refresh cadence |
91| Stale cached results | Source data changed but cache not invalidated | Use source data hash comparison before serving cache |
92| API rate limit (429) | Too many concurrent run triggers | Queue runs with concurrency limit of 3 |
93| Unused notebooks accruing runs | Abandoned projects still on schedule | Audit and disable schedules for inactive projects |
94| Connection pool exhausted | Too many simultaneous data source queries | Consolidate connections; stagger scheduled run times |
95
96## Prerequisites
97
98- An approved budget, baseline run/compute metrics, safe sandbox project, and named owner for each execution path.
99- A dry-run plan and rollback revision for schedule, cache, concurrency, and project parameters.
100
101## Instructions
102
1031. Measure aggregate run frequency, duration band, retries, cache behavior, and failure rate before proposing a control.
1042. Classify candidates as duplicate, expired, nonessential, or owner-review without inspecting or exporting workspace data.
1053. Dry-run the control, compare aggregate cost/run counts and safe project assertions, then canary one project.
1064. Promote only with owner approval; roll back for changed output shape, access scope, freshness, or increased failures.
1075. Keep a reversible revision and state savings as a range rather than an unsupported guarantee.
108
109## Output
110
111Return a cost-change receipt with baseline/projected runs, control revision, owner approval, canary result, aggregate assertions, estimated savings range, and rollback reference. Exclude SQL, output, and credentials.
112
113## Examples
114
115`project=proj-sandbox-12; baseline_runs=12000; deferred=120; deduped=900; assertions=pass; rollback=cost-r18` is a safe cost decision.
116
117## Resources
118
119- [Hex Pricing](https://hex.tech/pricing/)
120- Hex API Documentation
121
122## Next Steps
123
124See `hex-performance-tuning`.