← Back to insights

Serverless and Agentic Coding Are a Match Made in Heaven

Serverless gives AI coding agents the explicit architecture, clear boundaries, managed primitives, and smaller failure zones they need to make useful changes without inventing half the infrastructure themselves.

I am not going to spend this whole article making the usual serverless argument.

Yes, managed infrastructure is useful. Yes, automatic scaling is nice. Yes, not having to patch servers is a win. Yes, event-driven architectures can be a great fit for modern web applications.

All of that is true, but it is not the thing I want to focus on here.

The more interesting point is that serverless changes how useful agentic coding can be. It gives AI coding agents a better environment to work in. Not because the agents suddenly become smarter, but because the system they are working on becomes more explicit, more constrained, and easier to inspect.

That matters more than I expected.

When you build a web application, eventually it needs to be hosted somewhere. You can put it on a VPS, configure nginx, run your app with systemd or a process manager, add a database, bolt on a queue, and wire up whatever else you need. That is a completely valid way to run software. Plenty of serious production systems work that way.

But once you start using coding agents, a problem appears.

The agent may understand your application code, but not the environment around it. It may not know how your reverse proxy is configured. It may not know how background workers are started. It may not know which scripts run during deployment, which environment variables exist in production, which assumptions live in a README, or which parts of the setup are just tribal knowledge.

So when you ask it to make a meaningful architectural change, it has to guess.

Sometimes those guesses are fine. Sometimes they are not. The agent may invent a worker process that does not match how you deploy. It may reach for Redis because that is a common queueing answer, even though the rest of your system does not use Redis. It may assume local file storage is available. It may add a scheduler without understanding where that scheduler will actually run.

That is where serverless starts to feel less like a deployment choice and more like an agent-friendly development model.

In a good serverless application, the infrastructure is not hidden away from the code. The functions, queues, buckets, schedules, event sources, permissions, and environment variables are part of the application definition. They are visible. They can be reviewed. They can be changed alongside the business logic.

That gives the agent much better material to work with.

Context Is the Real Bottleneck

The limiting factor for coding agents is often not whether they can write code. They can write code all day. The limiting factor is whether they have enough of the right context to write the correct code.

A large application with hidden infrastructure assumptions is difficult for an agent to reason about. It might understand one handler perfectly while misunderstanding the system that handler lives inside.

Serverless helps because a lot of the system shape can be described compactly.

A serverless.yml file can tell the agent which functions exist, what triggers them, what resources they depend on, which environment variables they receive, and which permissions they have. It is not the whole system, and it is not always pretty, but it is a useful map.

That map is often much easier for an agent to work with than a scattered collection of deployment scripts, server configuration, process manager files, and undocumented runtime assumptions.

The other context win is that serverless applications tend to use managed services instead of custom code for infrastructure concerns.

If you use SQS, the agent does not need to understand your custom queue implementation. If you use S3, it does not need to understand a homegrown file storage layer. If you use EventBridge, it does not need to reverse-engineer a scheduler. If you use API Gateway, it does not need to invent a request routing layer at the edge.

The managed service becomes the primitive. The agent still needs to understand how your application uses that primitive, but it is no longer trying to figure out bespoke infrastructure before it can make a sensible change.

That changes the shape of the work quite a bit.

When the behaviour is known, documented, and represented in configuration, the agent has fewer places to hide bad assumptions.

The Agent Has Fewer Weird Directions to Wander Off In

Ask an agent to “make this async” in a normal web application and you may get almost anything.

It might add a Redis-backed queue. It might create a cron job. It might introduce a worker process. It might suggest Celery, BullMQ, Sidekiq, or whatever happens to fit the language and framework. It might edit a Dockerfile. It might add a command that needs to be run somewhere, by something, forever.

None of those options are necessarily wrong. The problem is that the agent is now making assumptions about the operational shape of your system.

In a serverless application, the obvious path is usually narrower.

The API function can write a message to SQS. A worker Lambda can consume from that queue. A dead-letter queue can catch repeated failures. IAM can allow the API function to send messages without allowing it to read or purge the queue. The worker can have its own timeout, memory setting, and permissions.

That narrowness is useful.

Serverless does not make the agent magically intelligent. It gives the agent rails. Instead of asking it to invent a background processing model, you are asking it to connect known primitives in a fairly standard way.

This is especially useful when you are working in small iterations. The agent can add the queue. Then it can add the worker. Then it can wire the event source. Then it can add the permission. Then it can update the handler. Each change has a clear purpose.

You still need to review the work, but you are reviewing a bounded change rather than a miniature infrastructure invention.

Architecture Becomes Readable Application Context

One of the things I like about serverless projects is that the architecture tends to be more visible in the repository.

Not always. You can absolutely make a serverless project incomprehensible if you try hard enough. A giant tangled config file full of functions, vague names, and copy-pasted permissions is still a mess.

But when it is structured well, the shape of the application is easier to see.

A Lambda function is not just code. It has an event source. It has permissions. It has memory and timeout settings. It has environment variables. It may be connected to API Gateway, SQS, S3, EventBridge, SNS, DynamoDB streams, or something else.

That is valuable context for an agent.

Imagine a feature where users upload images and the system generates thumbnails.

In a less explicit setup, the agent may need to infer where files are stored, how jobs are queued, how workers are started, where generated images go, and how the rest of the system finds them.

In a serverless setup, the flow can be much more visible. An image lands in S3. That event invokes a Lambda function. The function generates thumbnails and writes them to another bucket or prefix. Another event or message updates metadata somewhere else.

The agent can read that shape. More importantly, you can read the change the agent makes to that shape.

This is where serverless becomes genuinely useful for agentic coding. The infrastructure is not just a separate production concern. It is part of the application context.

Smaller Mistakes Are Easier to Recover From

Coding agents make mistakes. That is not a criticism. It is just the current reality.

Sometimes the generated code is subtly wrong. Sometimes it is correct but inefficient. Sometimes it loads too much data, does a database query in a loop, forgets an edge case, retries something that should not be retried, or handles an event shape too optimistically.

In a long-running application server, one bad path can have wide effects. A memory leak can degrade the whole process. Blocking work can affect unrelated requests. Mutable shared state can create strange behaviour. A concurrency bug can hide until the system is under load.

Lambda’s execution model is forgiving in a way that is useful when agents are involved.

A Lambda function receives an event, does some work, and returns. If the agent writes inefficient code inside one function, the damage is usually contained inside that function’s invocation boundary. It might run slowly. It might time out. It might cost more. It might fail a queue message. But it is less likely to take down the whole application runtime.

This does not mean performance stops mattering. It definitely matters. Inefficient serverless code can become expensive quickly, and bad retry behaviour can cause real problems.

But the failure is often easier to locate.

If the image processor times out, look at the image processor. If the SQS consumer is failing, look at the consumer. If the scheduled cleanup job is too slow, look at that function.

There is also a thread safety angle here, which is easy to understate.

Lambda does not remove all concurrency concerns. You still need to care about idempotency. You still need to handle duplicate SQS messages. You still need to think about two invocations updating the same database row. You still need to design around retries and partial failure.

But it does reduce a lot of process-level shared-state risk.

Most Lambda handlers can be written as straightforward event processors. Take input, do the work, persist state somewhere durable, return. There is less reason for the agent to rely on mutable in-memory state shared across unrelated requests. There are fewer long-running process lifecycle concerns for it to accidentally misunderstand.

That makes mistakes smaller, clearer, and easier to fix.

Not harmless. Just more contained.

Less AI-Generated Glue Code

One of the safest ways to use AI-generated code is to avoid generating code for things that should not be custom in the first place.

The risky parts are often not the obvious business logic. They are the bits around the edges. Queue handling. Retry loops. Scheduling. File storage. Worker lifecycle. Event dispatching. Permission checks. Internal orchestration.

That is exactly the sort of glue code agents are happy to produce, and exactly the sort of code I would rather not maintain if a managed service can do the job.

Serverless helps by replacing a lot of that glue with cloud primitives.

SQS can handle queueing and retries. EventBridge can handle scheduled events and event routing. S3 can handle object storage. API Gateway can handle HTTP integration. IAM can define function-level permissions.

The agent can then spend more of its time writing the small bit of application logic that belongs to you.

This is a better division of responsibility.

I would rather review a focused Lambda handler and a few lines of configuration than a generated worker framework. I would rather see an SQS event source mapping than a new custom polling loop. I would rather use EventBridge than let an agent invent a scheduler that only works if someone remembers to run it in production.

Less generated glue means less to distrust.

IAM Is Annoying, but at Least It Is Visible

Serverless does not make security automatic. You can still make a complete mess of it.

An agent can generate bad IAM. It can grant permissions that are too broad. It can expose an endpoint that should not be public. It can mishandle input. It can misunderstand which function should be allowed to touch which resource.

But serverless gives you smaller security boundaries to inspect.

A function that reads from one bucket can be granted access to that bucket. A function that publishes to one topic can be granted permission to publish to that topic. A worker that consumes from one queue can be given access to that queue and not every queue in the account.

When an agent adds permissions, you can review them next to the code that uses them.

That is a big improvement over a single large application process with broad credentials because different parts of the app all need different capabilities.

The nice thing about small functions is that excessive permission often looks obviously wrong. A report export worker probably does not need admin access to your database. A thumbnail generator probably does not need to list every bucket in the account. An email notification function probably should not be able to purge queues.

The smaller the unit of code, the easier it is to ask, “Why does this need that?”

That question is especially important when the change came from an agent.

Review Becomes Less of a Treasure Hunt

The goal of agentic coding is not to stop reviewing code. If anything, it makes review more important.

The useful thing about serverless is that review often becomes more local.

If an agent adds a new queue consumer, you can inspect the function, the queue, the event source mapping, the timeout, the batch size, the dead-letter queue, and the permissions. Those pieces are usually represented in the same project.

You do not have to go hunting through a server setup to check whether the worker will actually run. You do not have to wonder which process manager starts it. You do not have to ask where the scheduler lives. You do not have to infer whether a deployment script has been updated.

At least, not as often.

This is not a small thing. Review fatigue is real. If every agent-generated change requires archaeology across application code, infrastructure code, deployment scripts, and production assumptions, the agent becomes less useful.

A serverless project can still be complicated, but the complexity is more likely to be explicit.

That makes review less about discovering hidden context and more about judging the actual change.

Deployment Errors Are Useful Feedback

A lot of agentic coding is iterative.

The agent changes something. Tests or deployment fail. The agent tries to repair the failure. Sometimes this loop is productive. Sometimes it is painful.

Serverless tends to produce fairly bounded errors during that loop.

If the configuration is invalid, deployment fails. If a CloudFormation property is wrong, the error usually points at the resource. If a function lacks permission, the runtime error often tells you which action was denied. If the event payload shape is wrong, the handler fails in a way that can usually be reproduced with a sample event.

These errors can still be annoying. Anyone who has spent time with CloudFormation knows that “bounded” does not always mean “pleasant”.

But they are often concrete enough for an agent to work with.

A missing permission can be added. A resource reference can be corrected. A handler can be adjusted to match an event. A bad environment variable can be fixed. A timeout can be tuned.

That is harder when the failure depends on a hand-managed server, a stale process, a missing package, an undocumented startup command, or a reverse proxy configuration the agent cannot see.

The less invisible state there is, the better the repair loop becomes.

A Practical Example: Report Exports

A report export feature is a good example because it starts simple and then immediately becomes annoying.

The user clicks “Export”. The report might take thirty seconds. It might take three minutes. It should not block an HTTP request. The final file needs to be stored somewhere. The user needs to know when it is ready. Failures should retry, but they should not retry forever in silence.

In a traditional app, an agent asked to build this might make several reasonable but incompatible choices. It could add a local worker process. It could use Redis. It could create a cron-driven polling mechanism. It could store generated files on local disk. It could add a library that works locally but does not fit production.

In a serverless app, the shape is more obvious.

The API Lambda accepts the export request and writes a job to SQS. A worker Lambda consumes the job. The worker generates the report and writes it to S3. The database stores the export status and the S3 key. A dead-letter queue captures repeated failures. A status endpoint lets the frontend check progress, or an event can notify the user when the export is ready.

The agent can implement that in bounded pieces.

Add the queue. Add the worker. Add the event source. Add the bucket permission. Add the status update. Add idempotency. Add the failure path.

That is the kind of workflow where coding agents feel useful rather than reckless. The agent is not inventing an operational model from scratch. It is connecting known cloud primitives with application-specific code.

You still need to review the details. Is the queue message shape sane? Is the worker idempotent? Are the S3 permissions scoped properly? What happens if report generation succeeds but the database update fails? Can a user access someone else’s export?

Those are real questions, but they are the right questions. They are not questions about whether the agent remembered to create a process that will still be running next Tuesday.

The Constraints Are the Feature

The thing that makes serverless work well with agentic coding is not magic. It is constraint.

Serverless constrains how code runs. It encourages small execution units. It pushes durable state into managed services. It makes event sources explicit. It makes permissions visible. It reduces the need for custom infrastructure code.

Those constraints are useful for developers, but they are especially useful for agents.

A coding agent with too much freedom will often create more system than you asked for. It may invent abstractions, introduce new moving parts, or solve a standard cloud problem with custom code. Sometimes the result works. Sometimes it is a maintenance burden that arrived fully formed in a single pull request.

A well-structured serverless application narrows the agent’s options.

That does not make the output automatically good. It just makes the likely output easier to review and easier to correct.

This is also why I would not claim that serverless is always the right choice. It is not. A badly designed serverless application can turn into a distributed pile of tiny functions, vague events, broad permissions, and painful debugging. Agents can absolutely make that worse if you let them.

But when the project is structured well, serverless gives the agent a better set of defaults.

More of the architecture is readable. More of the infrastructure is expressed as application context. More of the work can be done by managed services instead of generated glue code. More of the mistakes are contained inside small functions. More of the security model can be reviewed at the function level.

That is why the combination works.

Not because serverless removes complexity.

Because it makes more of the complexity visible.

Want help applying this to your architecture?

Book a call and let's discuss what this means for your team.