Skip to content
Community content. Review instructions before giving them to an AI agent — treat modules like open-source code.

Serverless Conventions

Write serverless and edge functions that perform well and cost predictably: stateless handlers, cold-start budgets, timeout and memory sizing, idempotency for retries, database connection pooling, local dev parity, and cost awareness.

Mby @markdownersPublished August 21, 2026 · ~3 min read

0 downloads · Used by 0 stacks

A serverless function can be frozen, discarded, or run concurrently in dozens of isolated instances at any moment — never store state in memory between invocations, and never assume the process that handled the last request is the one handling this one.

Stateless handlers

  • Treat every invocation as if it's the first one on a brand-new instance — no in-memory cache, counter, or connection can be assumed to survive between requests, because the platform is free to spin up a new instance per request under load.
  • Persist anything that must survive across invocations (session state, counters, rate-limit windows) in an external store (database, Redis, KV), never in module-level variables assumed to persist.
  • Keep handlers pure with respect to global state: given the same input and same external state, the handler should behave the same regardless of which instance or how many concurrent instances are running it.

Cold-start budget

  • Keep the deployed bundle small and dependency count low — bundle size is one of the biggest levers on cold-start time, and an unnecessarily large dependency tree (a full ORM for one query, an entire SDK for one endpoint) is dead weight on every cold start.
  • Do expensive one-time setup (parsing config, creating a client) at module scope, outside the handler function, so it happens once per cold start and is reused across warm invocations — but never rely on it having run recently.
  • Avoid heavy synchronous work during initialization (large JSON parses, synchronous file reads) that blocks the first request on a cold instance — lazy-initialize anything not needed for every request.

Timeout and memory sizing

  • Set the function timeout deliberately based on the slowest expected legitimate request, not the platform default — a timeout that's too generous lets a hung dependency burn cost and delay error surfacing; one that's too tight kills legitimate slow requests.
  • Size memory based on actual profiling, not a guess — on most platforms memory allocation also scales CPU, so under-provisioning silently makes the function slower as well as more memory-constrained, and over-provisioning wastes cost linearly.

Idempotency for retries

  • Assume the platform may retry an invocation that times out or errors after partially completing (this is common on queue-triggered and scheduled functions) — write handlers so a retried invocation with the same input doesn't double-charge, double-send, or double-write.
  • Use the same idempotency-key pattern as background jobs (a dedup check on a natural or supplied key) for any serverless function with an external side effect.

Database connections

  • Never open a fresh database connection per invocation without pooling — serverless concurrency can spike to hundreds of simultaneous instances, each opening its own connection, and this exhausts a traditional database's connection limit almost immediately.
  • Use an external connection pooler (e.g. a pooling proxy sitting between functions and the database) or a database designed for serverless concurrency (HTTP-based drivers, built-in pooling) rather than the database's native connection protocol directly from every instance.
  • Reuse a connection across warm invocations by creating it at module scope, but always handle the case where a warm connection has gone stale (the platform froze the instance and the connection timed out server-side) and reconnect rather than erroring out.

Local dev parity

  • Run functions locally through the platform's actual emulator/CLI rather than a plain Node script that imports the handler — routing, environment variable injection, and request/response shape differ enough between "just calling the function" and the real invocation path that skipping this hides real bugs until deploy.
  • Keep environment variables and secrets configuration identical in shape between local and deployed environments, differing only in values, so a config-shape bug isn't discovered for the first time in production.

Cost awareness

  • Remember that serverless cost scales with both invocation count and duration — an accidental infinite retry loop or a function invoked in a hot per-item loop can produce a cost spike far faster than a fixed-capacity server would.
  • Set concurrency limits and budget alerts explicitly rather than relying on "it'll be fine" — the same elasticity that makes serverless convenient also makes runaway cost possible with no manual step required.
Badge

Link back to this module from your own README.

Get it on Markdowners
[![Get it on Markdowners](https://markdowners.com/mdstack-badge.svg)](https://markdowners.com/m/markdowners/serverless-conventions)

Comments (0)

Sign in to comment. Sign in

No comments yet. Be the first to add one.

Discussions about this module

No discussions about this module yet.

Start a discussion