Key takeaways
- Serverless means the provider manages the servers, not that servers do not exist.
- You pay per request and per unit of compute, which usually makes serverless cheapest for low or spiky traffic.
- Automatic scaling has quotas and downstream database limits that need deliberate planning.
- Cold starts and hard platform limits determine which workloads suit functions.
- Serverless suits event-driven, stateless, short-lived work; steady or long-running workloads often belong on servers or containers.
- Define resources as code, and set up monitoring, billing alerts and permissions from day one.
Serverless architecture is often presented as the answer to most cloud questions: no servers to manage, near-unlimited scale and a bill that grows only when customers use the product. Some of that is true. Some of it creates new problems that are rarely mentioned in the marketing, such as unexpected costs, failures that are hard to trace and limits that appear only under real load. Teams that adopt serverless without understanding these trade-offs often discover them at the worst possible moment.
Part of the difficulty is that the term is used loosely. Some people use it to mean functions that run on demand, others to mean any managed cloud service, and others to describe an application built without any server they have to think about. Those meanings lead to different decisions about cost, security, hiring and vendor choice. It helps to agree on what the term means before comparing options.
This guide explains serverless architecture in plain English. It is written for founders, managers, product owners and technical leads who need to make or review architecture decisions, as well as developers who are new to the model. It covers how serverless applications work, how billing and scaling behave, the hard limits and trade-offs, how serverless compares with virtual servers and containers, and where it fits well or poorly. Where a concrete figure helps, it uses AWS Lambda, the most widely used function service, but the principles apply to other providers as well.
If you are still deciding how your platform should grow, the guide to scaling infrastructure as your business grows places serverless within a wider sequence of decisions. The article on scaling a SaaS product and the infrastructure decisions that matter early covers the choices that are hardest to reverse later, and what infrastructure as code is and why it reduces errors explains how to define serverless resources in code from the start.
What "serverless" actually means
The name is misleading. Serverless applications still run on servers. The difference is that a cloud provider owns, patches and scales those servers, so your team never has to provision or maintain them. A useful comparison is a taxi versus owning a car. With a car, you pay for the vehicle whether or not you drive it, and you handle fuel, repairs and parking. With a taxi, you pay for the journey, and someone else looks after the vehicle. Serverless works the same way: you pay for the work your application does, not for machines sitting idle. The same idea of paying for what you use is covered in our guide to scaling infrastructure as your business grows.
In practice, serverless rests on three traits: no server management, automatic scaling, and payment for actual use. It is usually built from two halves.
Functions as a service
You upload a small piece of code, called a function, and the provider runs it whenever something triggers it, such as a web request, a file upload or a message arriving in a queue. The provider starts the function when needed, runs it and stops it afterwards. AWS describes its version of this model, AWS Lambda, as "a compute service that lets you run code without provisioning or managing servers" (source: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html).
Managed backend services
Alongside functions, providers offer ready-made services for storage, databases, queues, authentication and messaging. Your application calls these services rather than running its own copies. Together, functions and managed services replace the parts of an application that you would otherwise install, configure and maintain on machines of your own.
How a serverless application works
A serverless application is driven by events. Something happens, such as a file arriving or a visitor submitting a form, and that event triggers a function. The function runs for a short time, does its work and returns a result. Then nothing is running and nothing is billed until the next event arrives. Typical triggers include:
- An HTTP request sent through an API gateway
- A file uploaded to object storage
- A message placed on a queue
- A schedule, such as every night at 02:00
- A change to a record in a database
Consider a customer uploading a photo to a website. The upload lands in object storage, which triggers a function that creates a resized copy. That copy triggers a second function, which writes the image details to a database and sends a confirmation email. Each step is a separate, short-lived run, and the application is simply the chain of these reactions.
Functions are stateless. The execution environment that runs your code is temporary, so a function must not depend on files, variables or data left in memory or on local disk by an earlier run. Anything that needs to last, such as orders, user accounts or uploaded images, belongs in a managed database or object storage. For details of how the environment behaves, see the AWS Lambda documentation (opens in a new tab).
What you pay for and when serverless saves money
Serverless billing is based on use. On AWS Lambda, the most common example, you pay per request and for compute duration, measured in GB-seconds: the memory allocated to a function multiplied by how long it runs. Nothing is charged while the function sits idle. A third-party summary at https://www.cloudzero.com/blog/lambda-pricing/ lists, at the time of writing, $0.20 per million requests and $0.0000166667 per GB-second on x86, about 20% less on Arm. The free tier includes 1 million requests and 400,000 GB-seconds each month, and it does not expire after 12 months. Check the AWS pricing page for current rates, as these figures are not official and change over time.
Illustrative example: a function with 512 MB (0.5 GB) that runs for 200 ms per call, across 1 million calls, uses 0.5 × 0.2 × 1,000,000 = 100,000 GB-seconds. That is well inside the free tier, and the request count is within the free allowance too.
Why it can be cheap
- Low or spiky traffic costs little, because you pay only for the calls that actually happen.
- An internal tool used a few hours a day does not pay for a server that runs overnight and at weekends.
- There are no servers to patch or capacity to size in advance.
When it gets expensive
A constant, heavy workload can cost more than a reserved server or container, because you pay a premium for every request and every second of compute. Watch these cost traps:
- API gateway charges, which add to function costs on every request.
- Data transfer out of the cloud region.
- Logging, which can grow faster than the application itself.
- Provisioned concurrency, which bills reserved capacity even when no requests arrive.
- Developer time spent designing, debugging and monitoring a distributed setup. For a wider view of build costs, see how to reduce app development costs without sacrificing quality.
Automatic scaling and its limits
Serverless platforms run as many copies of a function as incoming events require. A burst of a thousand requests can trigger a thousand parallel instances, and when traffic stops, the platform scales back to zero, so idle capacity costs nothing. You configure no servers, load balancers or scaling rules. Automatic does not mean unlimited, however, and two limits catch teams out.
Concurrency quotas
AWS Lambda, for example, sets a default quota of 1,000 concurrent executions per AWS Region for new accounts. The quota applies to each Region separately and can be increased on request. Requests beyond it are throttled, so check your quota before launch and watch throttling metrics.
Protecting your database
The second risk sits downstream. Functions can scale far faster than the database behind them, and each instance may open its own connection. A sudden burst can overwhelm a database sized for steady traffic, causing timeouts and errors. To smooth the load:
- Set reserved concurrency on functions that call a database, so they cannot exceed what it can serve.
- Use connection pooling or a proxy so instances share connections.
- Place a queue between incoming events and slow work, so bursts are processed at a steady rate.
General autoscaling principles are covered in our infrastructure scaling roadmap. Databases are usually the first bottleneck, so review how database optimisation affects application speed before you raise any limits.
Hard limits and trade-offs you must know
Serverless platforms set hard limits that shape what you can build. The figures below are AWS Lambda's, taken from its documentation. Other providers set different limits, so check current documentation before you design around them.
Time and size limits
- The maximum function timeout is 900 seconds (15 minutes). Asynchronous invocations and some event source mappings can run for up to 5,400 seconds (90 minutes).
- Memory ranges from 128 MB to 10,240 MB, and CPU is allocated in proportion to memory. At 1,769 MB a function gets the equivalent of one vCPU.
- A zipped deployment package can be up to 50 MB when uploaded through the API or SDK. Larger packages must go through Amazon S3.
- Synchronous request and response payloads are limited to 6 MB each.
- The default quota is 1,000 concurrent executions per Region for new accounts.
Functions are also stateless, so any long job must be split into steps that save their progress outside the function.
Cold starts, why they cause problems and how to reduce them
When no warm execution environment is available, the platform must initialise a new one before the function runs. This delay is a cold start. It adds latency to the first request, which matters most for user-facing pages and APIs. To reduce it:
- Keep deployment packages small and remove unused dependencies.
- Choose a lightweight runtime and move heavy setup out of the request path where possible.
- Keep each function focused on one job.
- Use provisioned concurrency for latency-critical functions, accepting the extra cost of environments kept ready.
Lock-in, testing and debugging
Triggers, permissions and managed services such as queues and workflow tools are tied to one provider, so moving later takes real effort. Testing locally is harder because functions depend on cloud events. A single request may pass through several functions, so distributed tracing is needed to follow it. Keep business logic in plain code, separate from provider-specific glue code, so most of it can be tested locally and moved more easily.
Serverless vs servers vs containers
The three models differ mainly in who manages the infrastructure, how you are billed and how long work can run. With virtual servers you control the operating system and software, but you also patch, secure and scale the machines yourself. Containers, run through managed services such as AWS ECS, Google Cloud Run or Azure Container Apps, package your application with its dependencies and leave most host management to the provider. Serverless goes further: you deploy functions and the platform runs them only when something triggers them.
- Virtual servers: full control over the environment, but you manage patching and scaling, and you pay for each server while it runs, whether busy or idle.
- Containers: well suited to steady workloads and longer processes, with scaling rules you define and billing based on the capacity you use.
- Serverless: scales automatically, including down to zero, and bills per request and compute time, but each function must finish within platform time limits.
Start-up behaviour also differs. A server or container usually takes minutes to become ready, while a function can respond almost at once, although it may pay a cold-start delay after a period of inactivity. Serverless is rarely the simplest choice for work that must run for hours, where containers or servers are often easier to operate and cheaper.
The right architecture depends on the workload. In 2023, Amazon's Prime Video team moved a video quality monitoring service from serverless functions and microservices into a single application and reported about 90% lower infrastructure cost for that service. That is not an argument against serverless. Many real systems mix all three, with servers or containers for a steady core, containers for longer processes and functions for event-driven tasks. For a fuller discussion of how these choices change as a business grows, see our scaling infrastructure roadmap.
Where serverless fits well, and where it does not
Serverless suits work that arrives in bursts, runs for short periods and does not rely on state held in memory or on local disk. It is a poor match for work that runs for hours, needs steady heavy capacity, or depends on specialised hardware. The lists below explain why each case fits or does not.
Good fits
- APIs with variable traffic: you pay only for requests that arrive, and the platform adds capacity as demand rises without idle servers to manage.
- Webhooks: each incoming event is short and independent, so one function invocation per call is a natural match.
- File and image processing: an upload can trigger one function per file, and parallel runs finish a batch quickly.
- Scheduled jobs: a nightly or hourly task costs nothing between runs.
- Background tasks fed by a queue: the queue absorbs spikes while functions consume messages at a controlled rate.
- Data pipelines: small event-driven steps move and transform data in batches without a permanently running server.
- Prototypes and MVPs: there are no servers to patch and costs stay low until real usage arrives. Early products can suit serverless, but decisions about data and state still matter, because functions cannot keep anything locally.
- Lightweight backends for mobile apps and websites: irregular traffic and simple logic keep the backend small and cheap to run.
Poor fits
- Long-running jobs beyond the time limit: functions have a maximum run time, so large migrations or long video encoding need containers or batch services.
- Constant high-throughput workloads: steady heavy load makes per-request billing more expensive than a reserved server or container.
- Applications needing very low and predictable latency: cold starts add delay after idle periods, which hurts time-sensitive responses.
- Workloads needing specialised hardware or persistent connections: GPUs and long-lived WebSocket or database connections do not fit short-lived, stateless functions.
- Applications with heavy local state: anything held in memory or on local disk disappears between invocations, so it must move to external stores, adding complexity.
Security and operations in a serverless setup
Serverless moves part of the security work to your cloud provider, but not all of it. Under the shared responsibility model, the provider secures the data centres, the underlying servers and the function runtime. You remain responsible for your code, its dependencies, the permissions you grant and the data your endpoints expose.
Permissions and secrets
Give each function its own role with only the permissions it needs, so a compromised function cannot read every table in the account. Keep credentials out of code and configuration files, and store them in a secrets manager that the function retrieves at runtime. In practice, that means:
- Validate all input at the function boundary, including payloads from queues, webhooks and uploads.
- Keep dependencies updated and scan them for known vulnerabilities.
- Protect API endpoints with authentication and rate limiting.
Define functions, roles and permissions as infrastructure as code so every environment is built the same way and every change is reviewed. The approach is explained in What Is Infrastructure as Code and Why It Reduces Errors.
Monitoring and cost alerts
A single request can pass through several functions and managed services, so use structured logging and distributed tracing to follow it end to end. Set billing alerts so unusual spend is noticed quickly, and set concurrency caps so a bug or abusive traffic pattern cannot scale functions and their downstream costs without limit.
How to decide and where to start
The best way to judge serverless is with one real workload, not a whole platform. Work through the following steps in order.
- Pick one small, event-driven workload, such as resizing uploaded images or handling incoming webhooks.
- Estimate your monthly requests and average run time, then calculate the likely cost using the provider's current pricing, including API gateway, data transfer and logging charges.
- Check the provider's current limits for timeout, memory, payload and package size, and confirm the workload fits inside them.
- Choose a provider your team already uses, so you are not learning a new platform and a new billing model at the same time.
- Define the functions, permissions and services as infrastructure as code from the first deployment.
- Add monitoring, tracing and billing alerts from day one, and set a concurrency cap.
- Review the bill and the metrics after one month before deciding whether to expand.
Stay with a conventional setup if your workload runs at steady, heavy load, where a reserved server or container is usually cheaper, if jobs run for long periods, or if you have strict latency requirements that cold starts could break. Many teams keep their core application on servers or containers and move only event-driven tasks to functions. If you are unsure which pattern fits your application, the team at Zero One Creation can talk through the options with you using your own workload numbers.
Frequently Asked Questions
No. Servers still run your code, but the cloud provider owns, patches, scales and maintains them, so your team does not select, configure or pay for idle machines. Serverless describes who manages the servers, not whether they exist.
It depends on the workload. For low or spiky traffic, pay-per-request billing with no charge while idle is often much cheaper than a server that runs all month. For steady, heavy load, a reserved server or container is frequently cheaper, so compare the full cost, including API gateways, data transfer, logging and engineering time.
A cold start is the extra delay that occurs when the platform has to create a new function instance, for example after a period of inactivity or during a sudden burst of traffic. It matters most for user-facing requests that must respond quickly, and much less for background jobs or queue processing. You can reduce it by keeping packages small, choosing lighter runtimes and using provisioned concurrency where latency is critical, although provisioned capacity adds cost.
It can for many applications, particularly APIs, event-driven back ends and scheduled tasks combined with managed databases, object storage and authentication services. Applications with long-running processes, persistent connections, heavy local state or specialised hardware usually need servers or containers for some or all of their components. Many production systems mix all three approaches.
A container packages an application and its dependencies so it runs consistently anywhere, and you decide how many copies run and for how long, usually on a managed platform. Serverless functions are smaller units that the platform starts only when an event triggers them, and you pay for each execution. Containers suit long-running or steady services, while functions suit short, event-driven tasks.
Serverless removes some risks, because the provider maintains the underlying operating systems and infrastructure. It does not remove your responsibility for your code, its dependencies, permissions and data. Give each function only the permissions it needs, keep secrets in a secrets manager, validate input and protect public endpoints.
You can reduce lock-in but not eliminate it. Business logic written in standard languages is easier to move than code tightly tied to provider-specific triggers, databases and workflow services. Keeping integrations behind thin adapters, defining infrastructure in code and recording which provider services you depend on makes any future move less expensive.



