# Performance and warmup

Reduce email-check latency with HTTP connection reuse, signup-page warmup and bulk requests. Configure client pools and timeouts.

## Start with connection reuse

Reuse a server-side SDK client or HTTP pool when calling `https://api.irondome.dev`. SDK-owned transports provide pooling, bounded concurrency, request deadlines, and optional warmup. Configure the client once and keep it available across checks.

The main improvement is avoiding repeated DNS resolution, TCP connection setup, and TLS handshakes. Reuse a client for a stable endpoint and key instead of creating and closing one for every email.

| Runtime | Recommended lifecycle |
| --- | --- |
| Node.js | One SDK client per process or warm serverless instance |
| Python sync | One client per worker process, created after fork |
| Python async | One client per long-lived event loop |
| Go | Create `New(apiKey, Options{})` once; share it across handlers and goroutines |
| Rust | Create `Client::new(api_key, Options::default())` once; clones share its pool |
| Cloudflare Workers | Request-scoped portable SDK; the platform owns networking |
| Supabase / Vercel Edge | Portable Fetch client; follow the platform's invocation lifecycle |
| Native Deno | One owned HTTP client per server or warm instance; close after work drains |

See [Edge & Serverless](/docs/guides/edge-serverless) for platform-specific setup and transport selection.

## Prepare the signup connection

When a customer opens your signup page, you can start one `GET /healthz` from your backend using the same client that will later check their email. This can move connection setup into the time the customer spends filling the form.

```text
Customer opens signup
  → Your backend prepares its IronDome connection
  → Customer fills the form
  → Your backend checks the email using the same client
```

For a long-lived Node.js process, this helper coalesces simultaneous warmups and limits how often one process sends them:

```js
// Use the same module-scoped client as your signup handler.
let warming;
let lastWarmupStarted = 0;

export async function prepareSignup() {
  if (warming) return warming;
  if (Date.now() - lastWarmupStarted < 10000) return;
  lastWarmupStarted = Date.now();

  warming = client.warmup({ timeoutMs: 2000 })
    .catch(() => {
      // Optional preparation failed. The actual check still handles errors.
    })
    .finally(() => { warming = undefined; });

  return warming;
}
```

Call this from your signup page's server lifecycle alongside independent page work. For a static page, the browser can call a protected, rate-limited preparation route on your backend. That route uses this helper. Avoid an unrestricted endpoint that lets anyone generate warmup traffic.

This helper is for Node.js, where sharing a pool and in-flight promise within a process is valid. Do not share in-flight promises across Cloudflare Worker invocations.

## Keep the client available

Keep the client open between page load and form submission. The Node and Python SDKs default to about 20 seconds of idle retention. If typical form completion takes longer, an owned transport's idle policy can be increased—for example, Node's `idleTimeoutMs: 60000`—after evaluating idle socket usage.

That setting is a retention policy, not a guarantee that a connection lasts 60 seconds. The server, proxy, platform, or network can close it sooner. Keep-alive does not mean sending regular heartbeat requests. Do not poll `/healthz` to keep every customer's connection alive.

## What warmup helps

A successful warmup can prepare transport state on that client. It sends no email or API key and does not consume a check.

It does not validate your key, initialize the protected detector or quota path, pin a Fastly machine, or guarantee a warm connection in another backend instance. A direct browser-to-IronDome health request warms the browser's transport, rather than your backend's pool.

Do not put `await warmup(); await check()` in every signup submission. That adds an extra network round trip on the critical path. Start warmup earlier, or let the check establish its connection normally.

## Tune and measure

- Place your backend near your users and measure from that region.
- Keep one endpoint and credential configuration per client.
- Use bounded concurrency; more sockets can increase resource use without helping latency.
- Set request deadlines that leave time for your signup handler to respond.
- Measure the first request separately from subsequent requests, including p50 and p95.
- Record status and request ID when investigating failures. Redact keys and email bodies.

There is no universal latency number: routing, cold starts, server load, and network distance affect the result. Do not retry a timed-out check automatically; it may already have completed and counted toward usage.
