Skip to main content
3 min read

Limits & performance

A GDN app runs inside a sandbox with hard guardrails, so one app can never hang the panel or overload a data source. Most apps never come close to any of these — but when a render stops unexpectedly, it's usually one of them. Here they all are in one place.

Canvas

LimitValue
HeightAlways 32 px.
Width1–384 px. One panel module is 64 px wide; they daisy-chain (64, 128, 192, …).
Recommended widthKeep images to 192 px or smaller for best performance, and split content across pages instead of going very wide.

Anything drawn outside the canvas is clipped — it's not an error, it just doesn't show.

Drawing

Each page may issue at most 4096 draw operations. Every c.* call is one op (a helper like c.table expands into several). Go over and the render stops with:

error: op limit (4096) exceeded on a single page

If you hit it, you're almost certainly drawing per-pixel where a shape or helper would do — or you should split the screen across pages.

Time

Each render is killed if it runs longer than 30 seconds of wall-clock time:

error: render timed out (>30s) — possible infinite loop

That budget has to cover any http.get calls too (each with its own timeout, below), so in practice your own code should finish in well under a second. This limit exists to stop runaway loops — the usual trigger is a loop that never terminates.

On Glance's servers a render also runs under a CPU cap (~25 CPU-seconds) and a memory cap (~512 MB). Local previews on your own machine don't apply the CPU/memory caps, so an app that's fine locally can still hit them once published — keep renders light.

HTTP

http.get is the only network access, and it's bounded:

LimitValueWhat happens at the edge
Requests per render8 uncachedA 9th raises http limit: at most 8 …. Cache hits don't count.
Per-request timeout~4 secondsA slower endpoint returns status_code 0 (with resp["error"] set) instead of hanging.
Response size1 MBLarger bodies are truncated. Panel apps need kilobytes — pick a smaller endpoint.
MethodGET onlyPanel apps read data; they don't post it.
Default cache300 s (ttl_seconds)2xx responses are cached by (url, params, headers); repeat renders reuse them.

Because a slow API surfaces as status_code 0, always draw a fallback when resp["status_code"] != 200. Pick APIs that answer quickly — see where to find them.

Refresh

refresh: in the manifest sets how often the panel re-renders, in seconds:

ValueUse
60The practical floor — gdn check warns below it (refresh Ns is very fast).
300A good default (5 minutes).
3600Hourly data (weather, once-a-day counts).

A fast refresh doesn't make a still frame animate — it just re-fetches and redraws more often, which is harder on your data source and rarely needed. See How often your app redraws.

Inputs

An app may make 8 uncached requests per render regardless of how many inputs it has, and there's no fixed cap on the number of inputs — but every declared input must be read by your code, or validation fails it.

See also