Serverless is often discussed as a destination: remove servers, pay only for use, and scale automatically. Those statements describe a provider interface, not an architecture. Compute still runs on provisioned machines, idle capacity still exists somewhere, and an application still owns correctness when events repeat, limits are reached, or a managed dependency is unavailable.
A useful decision starts with a narrower definition. Serverless services allocate execution or managed capacity on demand, expose relatively high-level operational controls, and charge through consumption-oriented dimensions. In exchange, the platform controls more of placement, lifecycle, scaling, and runtime behavior. Functions are one form, but managed queues, workflow engines, event buses, databases, and container runtimes can participate in the same operating model.
The right question is therefore not “Can this code run as a function?” Almost any handler can. Ask whether the workload’s event model, state, latency, limits, cost curve, compliance needs, and team responsibilities fit the platform contract. The answer may be yes for one stage and no for its neighbors. Hybrid designs are normal, not failed serverless adoption.
Start With Workload Shape and Service Objectives
Describe demand before selecting a product. Record request or event arrival patterns, execution duration, concurrency, payload size, CPU and memory needs, network dependencies, and growth uncertainty. Separate the common case from scheduled bursts and rare extremes. A steady stream at predictable utilization has different economics and scaling needs from an unpredictable webhook burst that is idle overnight.
Classify the interaction too. An interactive request may have a strict end-to-end latency budget. A queue consumer may tolerate seconds of delay but require durable retry. A scheduled reconciliation can run for hours and checkpoint progress. A stream processor may need long-lived local state. “Backend code” is too broad a workload category.
Write service objectives and invariants independently of the platform:
- maximum accepted and completed latency for each operation class;
- required throughput during ordinary and burst demand;
- behavior under overload, including whether work may queue or be rejected;
- delivery semantics and tolerated duplication;
- recovery point and recovery time for state;
- regional, network, and data-residency restrictions;
- maximum sustainable cost at expected and stress demand.
Then identify the operational work the team wants to delegate: machine patching, process supervision, autoscaling, queue durability, database replication, certificate rotation, or deployment orchestration. Serverless can reduce undifferentiated operations, but it does not remove workload operations such as poison-message handling, schema evolution, cost controls, and incident diagnosis.
A poor fit often appears early. Specialized accelerators, privileged host access, stable local disks, custom network appliances, extremely long computations, or hard real-time deadlines may conflict with the platform. Do not hide those mismatches behind a proof of concept that exercises only a tiny happy path.
Match the Event Model Before the Handler
Serverless execution is strongest when work has a clear trigger, bounded inputs, an independently retryable unit, and no requirement that one process remain alive. HTTP requests, object-created events, queue messages, schedules, and workflow steps commonly fit. The trigger’s semantics matter more than the handler syntax.
Document who acknowledges an event and when. For a queue-triggered function, does the platform remove a message after the handler returns, after an explicit acknowledgement, or after a batch succeeds? If one item in a batch fails, are all items retried? How long is the visibility timeout? Can deliveries overlap? Where do exhausted retries go? Provider defaults are part of application behavior unless overridden.
Assume at-least-once delivery unless a stronger guarantee is explicit and end-to-end. A handler should derive an idempotency key from a stable event identity or business command, persist the outcome atomically with its state change, and return the stored outcome on duplicates. Ordering should be requested only where required because ordered partitions constrain concurrency and hot keys can dominate throughput.
Fan-out can turn a small input into surprising demand. One uploaded archive may produce thousands of object events, each calling a database and an external API. Per-stage concurrency limits and queues protect downstream systems from automatic scaling. A platform that can launch ten thousand invocations does not grant the database ten thousand safe connections.
Event schemas need versions, ownership, and compatibility rules. Managed routing makes producers and consumers easy to connect, which can conceal coupling until a field changes. Keep business events independent of provider envelopes where practical. Validate at ingress, preserve an event identifier and trace context, and quarantine malformed or permanently failing work instead of retrying it forever.
Separate Durable State From Ephemeral Execution
Function instances and scale-to-zero containers should be treated as disposable. Memory and temporary disk may survive a subsequent invocation, but that reuse is an optimization, not a correctness guarantee. Durable progress belongs in a database, object store, queue, or workflow service with a declared consistency model.
This does not mean every operation should make many remote calls. Coarse-grained handlers can load state once, perform a bounded unit of work, and commit one result. Extremely fine-grained functions often pay orchestration latency and request charges while making failure recovery harder. Choose boundaries around durable state transitions, not around individual source functions.
Long workflows need explicit state machines or persisted job records. A chain of direct asynchronous invocations can lose visibility into which step owns retry, compensation, and timeout. A managed workflow engine can store transitions and retries, but its history limits, pricing, and proprietary semantics enter the decision. A database-backed coordinator may offer more control at greater operating cost.
Connection management is a common constraint. Rapidly scaling handlers can exhaust a relational database even when CPU is available. Use a provider-supported proxy, a data service designed for high connection churn, or strict invocation concurrency. Reusing a connection within a warm instance can improve efficiency, but correctness and capacity must not depend on reuse.
Local caches have similarly weak guarantees. They can reduce repeated initialization, but invalidation and hit rates vary with instance churn. Put authoritative shared caches outside the execution environment and decide what happens when they fail. If the workload depends on large in-memory state or stable partition-local state for every event, a continuously running stream processor may be a better fit.
Treat Platform Limits as Design Inputs
Every serverless platform has ceilings: request and response size, execution duration, memory, temporary storage, environment size, deployment artifact size, concurrent invocations, event retention, workflow history, open connections, and API request rates. Some are adjustable quotas; others are hard product boundaries. Collect them before implementation and map each to a workload maximum.
Quotas compose. A queue may retain work for days while a function retries for minutes and a downstream API permits only a small request rate. Increasing function concurrency can shorten queue delay while triggering downstream throttling, which produces more retries and a larger queue. Model the whole path and set admission controls at the earliest practical point.
Latency includes routing, queueing, platform startup, application initialization, dependencies, and execution. Cold starts deserve measurement for the selected runtime, artifact, region, and traffic shape, especially on interactive paths. They are one term in the budget rather than a universal rejection or acceptance criterion. If measured startup variability violates the objective, choose a provisioned concurrency option, a continuously running service, or a different boundary; detailed prewarming tactics belong to performance engineering after the architectural fit is known.
Networking can be decisive. Private network attachment, outbound address stability, cross-region calls, DNS behavior, and managed-service endpoints affect both latency and security. Verify whether a scale burst also consumes scarce network interfaces or translation ports. A function reaching a database across regions is still a distributed system, even if both products have serverless labels.
Compliance review should include provider access, runtime patching responsibilities, execution regions, log and payload retention, encryption controls, and evidence available to auditors. Managed operation shifts responsibility; it does not erase it.
Work Through an Evidence-Package Pipeline
Consider a compliance product that accepts an evidence package, validates its manifest, extracts metadata from individual files, and produces a signed summary. Upload traffic is irregular: most organizations submit near reporting deadlines, while the service is quiet between cycles. Interactive users need quick upload acknowledgement, but final processing may take several minutes. Individual files are bounded, and the signing key must remain in an approved regional service.
The first design makes the upload endpoint small. It authenticates the organization, validates declared size and content type, creates a package record with an idempotency key, issues object-upload credentials, and returns. Object completion emits an event to a regional queue. A coordinator verifies the package manifest and writes one extraction command per file. Worker functions process bounded files, store immutable findings, and update completion through idempotent records. A workflow step builds the summary only after all required findings exist, then asks the managed key service to sign it.
This workload fits on-demand execution because arrivals are bursty, stages are event-driven, processing units are bounded, and durable state already lives outside workers. Queue buffering allows worker concurrency to remain below the metadata database and document-scanning provider limits. Duplicate object events are harmless because the command key combines package version and file identity.
Now add a requirement: some customers upload encrypted disk images that may require six hours of sequential analysis on a specialized high-memory runtime with a large local scratch volume. Forcing that stage into short-lived functions would require awkward chunking and expensive transfer. The pipeline instead routes ordinary files to functions and disk-image jobs to a managed container batch pool. Both write the same versioned finding contract. The admission, queue, state, and summary stages remain serverless; one compute stage does not.
Verification covers more than a successful demo. Replay the same object event concurrently and prove one finding becomes authoritative. Fail a worker after it writes output but before acknowledgement. Submit a package at maximum file count, throttle the scanner, and confirm queue growth remains bounded by retention and customer-facing status stays accurate. Test a malformed manifest, a poison file, regional key-service unavailability, and cancellation. Measure end-to-end latency by stage under representative burst arrivals, including the observed startup component, without presenting one local invocation as a fleet guarantee.
Model Cost Across the Demand Curve
Consumption pricing is attractive when idle periods are substantial and demand is uncertain. It can become expensive for steady high utilization, long execution, large memory allocations, frequent state transitions, verbose logs, or high data transfer. Compare complete workload cost, not function invocation price.
Build a model with provider-published units and your measured workload assumptions:
For execution, use arrival volume, duration distribution, allocated resources, retry rate, and concurrency. Include failed and duplicate work because providers bill it too. Add queue operations, workflow transitions, database reads and writes, object requests, log ingestion and retention, network egress, and any minimum provisioned capacity used to meet latency objectives.
Evaluate several points: expected demand, quiet periods, known bursts, and a stress case. Compare with a continuously running alternative using realistic utilization, redundancy, support, patching automation, and engineering effort. Do not claim people costs vanish under either model; identify which recurring tasks change.
Serverless pricing also changes cost risk. A bug or abusive event source can scale spending rapidly. Set account and service budgets, concurrency ceilings, event admission limits, maximum payloads, and alerts on cost-driving units such as invocations, duration, transitions, and log bytes. Billing alerts that arrive after a monthly threshold are not an overload control.
A break-even point is not permanent. Runtime efficiency, negotiated discounts, traffic shape, and product pricing evolve. Revisit the model when a workload becomes steady, provisioned concurrency grows, or managed-service charges dominate compute. Migration cost and operational disruption belong in that review.
Design Observability and Portability Honestly
An invocation log is not a request trace. Preserve correlation across ingress, event publication, retries, workflow transitions, functions, managed databases, and hybrid workers. Record event ID, schema version, attempt, queue age, selected route, durable state transition, and final outcome. Metrics should distinguish accepted, completed, retried, throttled, quarantined, expired, and duplicate work.
Managed platforms hide hosts but expose platform-specific failure signals. Monitor concurrency, throttles, initialization latency, execution duration, memory use, queue depth and age, dead-letter volume, workflow failures, database limits, and downstream saturation. Sample successful traces while retaining enough failed traces for diagnosis, and redact event payloads before logs become a second data store.
Local emulators help developer feedback but cannot establish production semantics. Integration tests in an isolated cloud environment should exercise actual identity, event delivery, networking, quotas, and deployment packaging. Keep deterministic domain logic in ordinary modules so it can be unit tested without the platform, while adapters translate provider envelopes and SDK errors.
Portability is a spectrum. Business rules, domain event schemas, idempotency logic, and state models can remain provider-neutral. Trigger configuration, identity policies, workflow definitions, database semantics, and observability are often provider-specific. Wrapping every API in a lowest-common-denominator interface can discard the managed capability that justified adoption.
Choose portability targets from credible scenarios. If regional regulation may require another provider, isolate provider adapters and maintain a tested data export. If the main concern is moving a hot function to containers, package its domain handler independently and preserve the queue contract. Document replacement cost rather than claiming “cloud agnostic” because handlers have generic names.
Decide, Pilot, and Revisit
A decision record should score the actual workload against event fit, state fit, latency, resource needs, limits, downstream capacity, security, observability, cost at several demand points, team skills, and exit cost. Mark unknowns. A short pilot should be designed to eliminate the riskiest unknown, such as private-network latency or maximum burst behavior, not merely prove that deployment succeeds.
Common failure modes are predictable:
- splitting one transaction into many tiny functions and paying in latency and recovery complexity;
- relying on instance memory or temporary disk for durable correctness;
- allowing automatic concurrency to overwhelm a database or external API;
- ignoring duplicate and reordered events;
- discovering hard duration or payload limits after the data model is fixed;
- treating provider dashboards as sufficient end-to-end observability;
- adopting proprietary orchestration accidentally while advertising easy portability;
- comparing per-request charges with server compute while omitting surrounding managed services;
- making all workloads serverless to satisfy a platform standard.
Test operational controls before launch. Exercise concurrency ceilings, queue retention, poison-event quarantine, replay, regional failure, deployment rollback, credential rotation, cost alerts, and data restoration. Run load shapes that include idle-to-burst transitions and sustained demand. Verify both service objectives and downstream safety.
Revisit the decision when traffic shape, latency objectives, platform limits, regulation, or team ownership changes. Moving a steady processor to containers can be a normal optimization; moving a bursty edge back to functions can be equally sensible. Preserve contracts so execution choices can evolve independently.
Serverless architecture is strongest when its managed lifecycle matches the workload rather than when it maximizes the number of functions. Event-shaped, bounded, independently retryable work can gain elastic capacity and reduced infrastructure operation. Stateful, specialized, long-running, or tightly latency-bound work may belong elsewhere. By evaluating limits, complete costs, failure semantics, and operational evidence up front, teams can use serverless where it transfers useful responsibility and keep conventional compute where control is the more valuable property.