In a Postman collection, what does hanging the token-fetch pre-request script on the collection cost?
answer
- The collection is not the only place an event hangs
- Ancestors' listeners join every item's pre-request work
- Count the calls, not the scripts
- Move it down, or make repeats free
- A cached value plus an expiry check
basics
~20 sA prerequest event declared on the collection runs before every request in the run, so a token-fetch script there makes one extra call per request. Moving it to a folder, or caching the token in a variable, removes that.
solid answer
~40 sThe collection document declares its own `event` array, the same field a folder and a request each declare — and when the runtime prepares an item it gathers the `prerequest` listeners on that item *and* on every ancestor. So a fetch script on the collection is part of every item's pre-request work: one call to the identity service per request, multiplied again by a run over data rows. Two fixes. Move the `event` down to the folder that actually holds the authenticated requests, or keep it on the collection and guard it — read a cached token and its expiry out of a scope and skip the call while it is still valid. Neither touches the auth block: `accessToken` still reads the same brace token.
code
javascript · 11 linesconst token = pm.collectionVariables.get('access_token'),
expiry = Number(pm.collectionVariables.get('access_token_expiry'));
if (!token || Date.now() >= expiry) {
pm.sendRequest({ url: pm.environment.get('token_url'), method: 'POST' }, function (err, res) {
if (err) { return; }
const body = res.json();
pm.collectionVariables.set('access_token', body.access_token);
pm.collectionVariables.set('access_token_expiry', Date.now() + body.expires_in * 1000);
});
}go deeper
Know that a pre-request script can hang on the collection, on a folder, or on a single request, and that the collection is the widest of the three choices.
Explain that ancestors' listeners join every item's pre-request work, so a fetch on the collection is one call per request, and name both fixes: relocate the event or guard the script.
Diagnose it from the run's request history, and write the guard correctly — a stored expiry, a safety margin, and a scope the run still holds when the request is prepared.
Decide when uniform authentication justifies a collection-wide declaration with a cache versus a narrower folder-scoped one, and set the convention so suites do not rediscover it each time.
## What "hung on the collection" means The collection document declares its own `event` array — the same field a folder (`item-group`) and a request (`item`) each declare. A `prerequest` entry there is **not** scoped to one request. When the runtime prepares an item it gathers the `prerequest` listeners declared on that item *and* on every ancestor above it, so a script sitting on the collection is part of every single item's pre-request work. For a script that only sets a header or logs a line, that is free. For a script whose body is an out-of-band call to an identity service, it is a real cost multiplied by the size of the run. ## The arithmetic - One token call per request, not one per run. - A run repeated over data rows multiplies that again — every request of every iteration. - Each call is real network latency on the critical path, in front of a request that was already going to take network latency. - The credential is very often valid for far longer than the entire run takes. - On a shared identity service, a suite that hammers the token endpoint is also the suite that gets throttled first. ## Placement is the lever | Where the `event` hangs | Runs before | Right when | |---|---|---| | the collection | every request in the run | genuinely every request needs the credential | | a folder | every request inside that folder | only one area of the collection is authenticated | | the request | that one request | one call needs a different credential from the rest | Moving the `event` down is the smallest possible fix, and it is usually the honest one: the requests that need a token are rarely *all* of them. ## The second fix: make the script idempotent If the fetch really does belong on the collection — because every request is authenticated — leave it there and make repeat executions cheap. The script reads the cached token and a stored expiry out of a scope, skips the call while the value is still good, and fetches only when it is missing or stale: ```javascript const token = pm.collectionVariables.get('access_token'), expiry = Number(pm.collectionVariables.get('access_token_expiry')); if (!token || Date.now() >= expiry) { pm.sendRequest({ url: pm.environment.get('token_url'), method: 'POST' }, function (err, res) { if (err) { return; } const body = res.json(); pm.collectionVariables.set('access_token', body.access_token); pm.collectionVariables.set('access_token_expiry', Date.now() + body.expires_in * 1000); }); } ``` The script still runs before every request. It just stops *calling out* before every request, which is the part that costs. ## What does not change either way The auth wiring is untouched by both fixes. The `accessToken` attribute still holds the same brace token, and the runtime still resolves variables into the auth before it hands the auth to the handler that signs. Relocating or guarding the script changes **how often the token is fetched**, never **how it is read**. That separation is the point of the indirection: acquisition and consumption are joined only by a variable name, so you can change one without touching the other. ## Signals you have this problem - The token endpoint appears in the run's request history once for every functional request. - A run's wall-clock time is roughly double what the requests themselves account for. - The identity service starts refusing calls partway through a long run. - A single-request run passes and the full run does not. ## The judgement call Reach for relocation first, because it is declarative and leaves no code to be wrong. Reach for the guard second, when the collection really is uniformly authenticated. Reach for both when a large collection has one authenticated subtree that is itself large — the folder narrows *which* requests trigger the script, and the guard makes the repeats within that folder free.
- Moving the event to a folder narrows which requests trigger it. What does it not change?How the token is read. The `accessToken` attribute still holds the same brace token, and the runtime still resolves variables into the auth before the handler signs. Placement decides how often the value is fetched; the auth block decides how the value is consumed. That is the point of joining them only by a variable name — either side can move without the other.
- When would you keep the fetch on the collection despite the repetition?When the collection is uniformly authenticated, so a folder would not narrow anything, and the script is guarded so repeat executions do not call out. You get one declaration covering every request, at the cost of a cache key and an expiry to maintain. If only a subtree is authenticated, relocation is the cheaper and more honest fix.
saying these in an interview costs you the question
- Thinks a collection-level script runs once at the start of a run
- Assumes the auth block caches the token between requests automatically
- Believes moving the event changes how the token is read
- Caches the token without storing or checking an expiry
- Blames the runner's speed rather than counting the token calls