A server is a process, not a building
Run this on your laptop:
$ node server.js
Listening on http://localhost:3000You are now running a server. A program is holding a TCP port open and answering whatever arrives on it. That is the whole definition. Nothing about a rack, a cooled room in Mumbai, or a company with a blue logo is part of it.
What your laptop lacks is not server-ness. It lacks three things: a public address (your router gave you a private one like 192.168.1.7), a certificate so browsers trust it, and the willingness to stay awake when you close the lid. Deploying is buying those three things from someone else.
What you are actually renting
There is a ladder, and the rungs differ in how much of the machine you are responsible for.
- Bare metal. A physical computer in a building. You get all of it, you patch the kernel, you care when a disk dies.
- Virtual machine. A slice of that computer, with its own Linux, its own IP, root access. A DigitalOcean droplet, an EC2 instance, a Hetzner box. Small ones run about $4–7 a month.
- Container platform. You hand over an image, the platform runs copies of it and restarts them when they die. Fly, Render, Cloud Run.
- Serverless. You hand over a function. It runs when a request arrives and stops afterwards. Lambda, Cloudflare Workers, Vercel functions.
"The cloud" means only this: someone else owns the machine, the building, the power and the network, and bills you by time or by request. It is a rental agreement, not a technology.
The axis that actually changes your code
Forget price for a moment. The question that changes how you write things is: is a process always running?
Always-on, you get a process with memory that persists. You can hold a database connection pool. You can keep an in-memory cache. You can start a timer that fires every ten minutes. You pay the same at 3am with zero visitors.
Per-request, a process starts when a request arrives — 50 to 500ms of cold start if none is warm — handles it, and may be gone before the next one. Consequences people discover the hard way:
- A module-level cache is usually empty, because the next request lands on a different instance.
setIntervalfor a nightly job never fires. You need the platform's scheduler.- Every instance opens its own database connection. Postgres defaults to about 100 connections. Fifty concurrent instances plus a pool of five each is 250, and you get
sorry, too many clients already. This is why serverless projects put a connection pooler in front of the database.
Neither shape is better. They fail differently, and the failures are only surprising if you did not know which one you picked.
The machine is in a place
Regions are not marketing. A round trip from Lagos to a Virginia region is roughly 110–180ms. Frankfurt might be 60ms. That is per round trip — if your handler runs ten sequential queries against a database on another continent, you have built a two-second page out of fast code.
The rule that matters more than any other: put your application in the same region as your database. Users are far away once. Your database is far away on every query.
So what is a deploy
Get the code onto a machine that has a public address, run it, point a name at it, keep it running. Everything else is convenience.
Before you move on