Learning objectives
After reading this article you will be able to:
- Understand the difference between a serverless function and a container
- Recognize limits such as timeouts, cold starts and persistent connections
- Pick the right model for a bot or an API
Almost everyone who ships a bot or an API hits the same question: deploy a function that runs only when called, or a container that stays up all the time. Both work, but they solve different problems, and the wrong pick shows up as timeouts, a bot that drops offline, or a bill that does not add up.
The comparison below uses the criteria that matter in practice: execution time, persistent connections, cold starts, state and cost. The limits quoted come from the AWS (Lambda), Google Cloud (Cloud Run) and Discord documentation. These values change from time to time, so check each provider's official page before you design around them.
What is serverless?#
With serverless (also called FaaS, "function as a service"), you ship a function. The provider creates an execution environment when a request or event arrives, runs the function, then freezes or discards the environment. You do not pick a machine or maintain an operating system, and the number of environments follows demand, down to zero when nobody calls.
The classic example is AWS Lambda. A Telegram webhook in Python fits in one function:
import json
import os
import urllib.request
def handler(event, context):
# Reject calls without the secret_token set in setWebhook
headers = event.get("headers") or {}
if headers.get("x-telegram-bot-api-secret-token") != os.environ["WEBHOOK_SECRET"]:
return {"statusCode": 401, "body": "unauthorized"}
update = json.loads(event["body"])
msg = update.get("message")
if msg and msg.get("text") == "/ping":
payload = json.dumps({"chat_id": msg["chat"]["id"], "text": "pong"}).encode()
req = urllib.request.Request(
f"https://api.telegram.org/bot{os.environ['BOT_TOKEN']}/sendMessage",
data=payload,
headers={"Content-Type": "application/json"},
)
urllib.request.urlopen(req, timeout=5)
return {"statusCode": 200, "body": "ok"}With a Function URL, the request body arrives as text in event["body"], and the X-Telegram-Bot-Api-Secret-Token header carries the secret_token you set in setWebhook. Each message becomes one invocation. Between invocations, none of your processes is running. Compare that with long polling, where a process keeps asking for updates.
What is a container?#
A container is an isolated process, packaged with its dependencies, that runs continuously until you stop it. For the technical background, see what is Docker and containers vs virtual machines. For a developer, the deciding difference is this: your code starts once and keeps memory, connections and timers open.
A Discord bot using the Gateway is the typical case:
import { Client, Events, GatewayIntentBits } from "discord.js";
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once(Events.ClientReady, (c) => console.log(`Online as ${c.user.tag}`));
client.on(Events.InteractionCreate, async (interaction) => {
if (interaction.isChatInputCommand() && interaction.commandName === "ping") {
await interaction.reply("pong");
}
});
client.login(process.env.DISCORD_TOKEN);This process has to stay alive to receive events. If it dies, the bot goes offline (see how to keep a bot running 24/7).
What are the limits of serverless?#
Limits vary by provider, but those of standard AWS Lambda functions show the shape (newer Lambda variants have their own limits):
- Duration: one invocation runs for up to 900 seconds (15 minutes).
- Memory: 128 MB to 10,240 MB, with CPU scaling in proportion to the memory you set.
- Payload: 6 MB for the request and for the response on synchronous calls.
- Disk:
/tmpbetween 512 MB and 10,240 MB, with no guarantee it persists. - Environment: Lambda reuses environments for a while but retires them every few hours, so code cannot assume state survives.
Google Cloud Run, which runs containers on demand, shows the line between the models is blurrier than it looks: its default request timeout is 5 minutes and can go up to 60 minutes. Even so, the application still has to accept that its process can be created and destroyed at any moment.
What is a cold start and when does it hurt?#
A cold start is the cost of the first invocation in a new environment: downloading the code, starting the runtime and running the initialization outside the handler. According to AWS, it ranges from under 100 ms to over 1 second and happens in under 1% of invocations. For an API with regular traffic, that is nearly irrelevant. For an endpoint called rarely, almost every call pays the delay.
It matters when the response deadline is short. Discord requires the initial response to an interaction within 3 seconds, and the interaction token is valid for 15 minutes for follow-ups. A cold start plus a slow database query can blow that deadline. The fix is to send a deferred response right away and edit the message later.
Providers offer mitigation, such as Lambda's provisioned concurrency, which keeps environments ready. At that point you are paying for idle capacity again, which is what a container already does.
Why don't Gateway bots and WebSockets fit serverless?#
The Discord Gateway is a persistent WebSocket. The connection needs heartbeats at a regular interval, and if your app fails to send one in time, Discord closes the connection and you have to resume the session. A function capped at 15 minutes with a disposable environment cannot hold that. The same goes for any WebSocket server, for workers that consume a queue continuously and for WhatsApp bots that depend on an open session.
There are two real exceptions. Discord bots can receive commands over HTTP (Interactions through an endpoint) without the Gateway, and a function is enough there, but you lose events such as messages and presence. And a Telegram bot in webhook mode works well on serverless, because each update arrives as a request.
How do the two compare side by side?#
| Criterion | Serverless (function) | Container |
|---|---|---|
| Deploy unit | A function and its handler | A process or image |
| Run time | Limited (e.g. 15 min on Lambda) | Continuous, as long as the process lives |
| Persistent connection | No | Yes |
| In-memory state | Not reliable | Kept while the process lives |
| Cold start | Yes | Only when the process starts |
| Scaling | Automatic per request, down to zero | You set the RAM and instance count |
| Typical billing | Per invocation and duration | Per reserved capacity |
| Good for | Webhooks, short jobs, spiky traffic | Bots, WebSockets, queues, steady APIs |
| Watch out for | Timeouts, payload limits, cost at high volume | Restarts, logs and sizing are on you |
There is no universal winner. Cost depends on the traffic pattern: few calls favor paying per invocation, steady load favors fixed capacity. Run the numbers with your own volume before deciding.
Which one should you pick?#
- Discord Gateway bot, music bot or WhatsApp bot with an open session (Baileys, whatsapp-web.js): container.
- Telegram bot: either works. Webhooks fit serverless; long polling needs a running process.
- REST API with steady traffic: container, for predictable cost and no cold start. See how to host an API.
- API or webhook with rare spikes: serverless tends to pay off.
- Short scheduled task: serverless, or a cron job inside a container.
- Long task, batch processing: container, because of the duration cap.
A hybrid is also common: the core runs in a container and one or two functions handle occasional events.
How to do this on Square Cloud#
Square Cloud uses the container model: each application runs in an isolated container that is always on, with no cold start and no sleep mode. Automatic restart is on by default for dashboard deploys and brings the app back when the process exits with an error. Because the container never sleeps and the proxy does not cut long WebSocket connections, Gateway bots, WebSocket servers and workers run without changes.
You deploy by ZIP upload in the dashboard, with the CLI, through GitHub or with the VS Code extension, and choose from several runtimes, such as Node.js, Python, Go and Java; see the ones available today on Runtimes.
Scaling is vertical (you change each application's RAM) or horizontal through load balancing: from the Standard plan up, you put the same custom domain on several applications, served round-robin. There is no autoscaling: you set the capacity. The full list is in Square Cloud features.
Deploy
Push from GitHub, the CLI or a ZIP and go live in seconds
FAQs
Is serverless cheaper than containers?
It depends on usage. With few, scattered requests, paying per invocation is usually cheaper. With steady traffic or an always-on process, a fixed-size container tends to have more predictable costs.
Can I run a Discord bot built with discord.js on serverless?
Not with the Gateway model, because it needs a WebSocket connection open all the time. It only works if the bot uses HTTP-based Interactions alone, which Discord sends as plain requests.
What is a cold start?
It is the extra time of the first invocation in a new environment: downloading the code, starting the runtime and running initialization. Later invocations that reuse the environment skip that cost.
Does serverless really have no servers?
It has servers. The name means you do not provision or maintain the machine: the provider decides where and when your code runs.
More in Deploy
See all 33 articles- What are environment variables?Environment variables are key-value pairs the operating system hands to a process at startup. Learn to read them in Node.js and Python and keep tokens out of code.
- What is a deployment?A deployment takes a version of your code to a server, prepares it and starts it. See the stages, the methods and how to roll back when it goes wrong.
- How much RAM and CPU does my app need?Size RAM and CPU by measuring your app's real peak and adding about 30% headroom. Learn how to measure in Node.js, Python and Java and what to do if short.
- Automatic deploys with GitHub ActionsAutomatic deploys with GitHub Actions ship your code to the server on every push. See the workflow step by step, secrets, tests before deploy and common errors.