A project that runs beautifully on one laptop is invisible to everyone else. Deployment is the move that changes that: the app leaves the machine where it was built and lands on computers that are always on, where a link, not proximity, decides who can use it. For vibe coders, this step carries more unfamiliar vocabulary than any other, yet almost none of it requires writing code.

This lesson translates that vocabulary into plain language: what hosting, domains, DNS, and production actually mean, and why the deployed version of an app behaves differently from the local one. It draws heavily on Andrej Karpathy's firsthand account of shipping MenuGen, where building was the easy part and making it real meant a slog of accounts, settings, and configuration.

It also maps the sharing ladder, the honest range of options from a hosted artifact link to a fully deployed app with its own domain. Most projects belong on a lower rung than their builders assume, and knowing the whole ladder makes that placement a choice rather than an accident.

What does deploying mean?

Deploying means moving software from the machine where it was built onto computers that are always on and reachable by anyone. Before deployment, an app lives on "localhost," the local version only its builder can open; after deployment, a URL grants access to anyone who has it, whether the builder's laptop is awake or not.

The distinction matters because the two versions feel identical but behave nothing alike. Andrej Karpathy, who coined the term vibe coding, called building his app MenuGen an "exhilarating and fun escapade as a local demo, but a bit of a painful slog as a deployed, real app" [1]. The local demo was the fun part; making it real meant hosting accounts, configuration, and settings screens.

For vibe coders, the encouraging news is that this slog is mostly administrative rather than technical. Deployment asks for patience with accounts and settings, not for a sudden leap into serious programming.

Hosting, domains, and DNS

Three terms cover most of deployment's vocabulary. Hosting is renting always-on computers to run the app, so it stays reachable when the builder's laptop is closed. A domain is the human-readable name, like menugen.app, that people type or click. DNS is the address book connecting the two: records that point the name at the computers doing the hosting.

In practice, the pieces arrive in this order:

  • Hosting comes first; a hosting account gives the app a working address right away, usually a free subdomain
  • A domain is bought separately, from a registrar, and only when the project wants an identity of its own
  • DNS records are edited last, telling the internet that the new name should lead to the hosted app

When Karpathy deployed MenuGen, exactly this sequence played out: a hosting account on Vercel, then buying menugen.app, then changing DNS records so the name pointed to the app [2]. Jakob Nielsen argued back in 1999 that domain names are part of the interface itself, so when a name is chosen, memorable and spellable beat clever [3].

What is production?

Production is the version of an app that real people rely on, as opposed to development, the version the builder experiments with. A useful working contrast: development is the version that's allowed to break; production is the version other people are allowed to depend on. Uxcel's glossary captures the endpoint with General Availability, the stage when software is fully tested, documented, and supported [4]. Production is a promise, not a place.

Real services enforce the distinction. When Karpathy deployed MenuGen, his login provider Clerk ran happily in "Development" mode but refused to switch to "Production" until he owned a custom domain [5]. The label wasn't decorative; it changed what the service demanded.

The implication for vibe coders: production isn't a quality tier; it's a responsibility tier. The moment other people depend on an app, its builder has made a support promise, whether intended or not. For a personal tool with three users, the lightest hosting rung is the right production.

The sharing ladder

The sharing ladder

Putting something on the internet isn't one move; it's a ladder, and each rung trades convenience for control. The lightest rung is sharing a hosted link: platforms like Claude publish an artifact with one action, host it themselves, and let anyone view it without an account, all inside a sandbox that can't reach other services [6]. The middle rungs are platform one-click publishing and static hosting; Simon Willison serves more than 80 vibe-coded tools as plain static pages, where hosting is nearly free because there's no server to break or breach [7]. The top rung is a real deploy with its own hosting, domain, and services.

The right rung is the lightest one that serves the actual need, not the one that feels most "real." A custom domain and full infrastructure signal legitimacy, which makes over-climbing tempting. Karpathy reached the top rung with MenuGen and then wondered whether it should've been a full-featured app at all [8]. Willison makes the safety case for the bottom rungs: sandboxed platforms make it very difficult to cause harm by accident [9].

Pro Tip! Starting one rung lower than feels impressive is rarely a mistake; climbing later is always an option.

The IKEA furniture problem

A modern app isn't one thing; it's a bundle of separate services, each with its own account, documentation, API keys, settings, and pricing tier. Karpathy compared assembling them to putting together IKEA furniture: the hard part of making MenuGen real wasn't the code but wiring together hosting, payments, login, database, and domain services, one flat-packed piece at a time [10]. Reflecting a year later, he repeated the point: the DevOps assembly, not the code, was by far the hardest part [11].

His own time log makes the shape of the work clear: "I didn't even spend all that much work in the code editor itself. I spent most of it in the browser, moving between tabs and settings and configuring and gluing a monster" [12].

The reframe matters for expectations. The slog is administrative, not intellectual: patience with accounts and settings, not sudden coding skill, is what deployment demands. Administrative doesn't mean trivial, though; the settings screens are where costs, access, and safety get decided.

Works on my machine

Code that runs perfectly locally can fail the moment it's deployed, and the failure says nothing about the builder's competence. Hosting platforms run stricter checks than a local setup does, and settings that live on the builder's machine, like API keys, don't travel automatically; they have to be re-entered in the hosting platform's own configuration.

MenuGen is the canonical example: the app worked locally, then its build failed only on Vercel, tripped up by stricter checks and missing environment keys. Karpathy, an elite programmer, burned an hour on it and noted, "I could see an aspiring vibe coder get stuck on this for a while" [13].

The takeaway is expectation-setting: a deployed version that breaks in ways the local one didn't is normal, not a sign that something has gone deeply wrong. Treating the first deploy as a debugging session of its own, rather than a victory lap, saves a lot of frustration.

Public by default

Nothing about a deploy guarantees privacy. When Karpathy connected his private, unfinished MenuGen repository to Vercel, the platform put it "on a totally public and easy to guess url just like that" [14]. Sharing scope is a decision the platform makes unless the builder makes it first.

The instinct to trust the default comes from ownership: it's the builder's project in the builder's account, so surely it stays private. It doesn't, and public things get found mechanically rather than by luck. The leojr94 launch from lesson 5.1 makes the stakes concrete: a publicly launched app came under active attack within roughly two days [15].

Deployment is also the moment the 5.1 safety checklist stops being theoretical. Running it before the link leaves the builder's hands, rather than "once people actually use it," is the difference between shipping a choice and shipping an accident.

Pro Tip! The first setting worth checking after any deploy is who can see it, before the link goes anywhere.

"Deployed means done"

The idea that shipping is the finish line comes from physical products, where the work genuinely ends when the item leaves the factory. Deployed software works the other way: going live is when obligations start accruing rather than ending.

Deployed apps keep demanding attention because:

  • External services change; both of MenuGen's AI services had already changed their APIs mid-build [16]
  • Free tiers lapse, and real usage starts costing real money
  • Users find edge cases the builder never imagined

Uxcel's definition of General Availability builds support directly into the meaning of shipping [17]. Production is the state in which maintenance pressure starts accumulating, and that pressure is exactly what the next lesson's graduation question is about.

Is a custom domain necessary?

No rung of the sharing ladder below "real product" requires buying anything. An artifact link, a platform subdomain, and a static page all come with a free address included. Karpathy bought menugen.app not out of preference but because his login provider's production mode refused to run without a custom domain the builder owns [18]. The purchase was a requirement imposed by one service, not a rite of passage.

When a project does earn its own name, the name deserves care. Jakob Nielsen argued in 1999 that the URL is part of the user interface: people guess, remember, and retype names, so memorable and spellable beat clever [19]. The principle has aged well even as sharing moved toward messaged links and QR codes; the address is part of the experience wherever it appears.

The practical answer for most vibe-coded projects: skip the domain until something specific demands it, whether that's a service's production requirement or a genuine need for an identity of the project's own.