{"course":{"slug":"building-apps-with-ai","title":"Building Apps with AI","url":"https://addaly.com/learn/building-apps-with-ai","level":"beginner","track":"build"},"lesson":{"slug":"deploying-for-a-stranger","title":"Deploying so a stranger can open it","url":"https://addaly.com/learn/building-apps-with-ai/deploying-for-a-stranger","position":44,"of":87,"minutes":8,"answer":"Production differs from your laptop in configuration, case sensitivity and users, so deploy on day two, not week three.","keyIdea":"Production differs from your laptop in configuration, case sensitivity and users, so deploy on day two, not week three."},"body":{"format":"markdown","text":"## localhost is not the internet\n\n`http://localhost:3000` means \"this computer.\" Sending that link to a friend sends them to their own machine, where nothing is listening. This trips up everyone once.\n\nTo put your app somewhere a stranger can reach it, four things have to exist away from your laptop: your code, a machine to run it, your configuration, and your data.\n\n## Where it can live\n\nIf you built on Replit, Lovable or Bolt, there is a deploy button and the platform handles all four. Use it. The rest of this lesson still matters, because the differences below still apply.\n\nIf you have your own repository, the common hosts are Vercel, Netlify, Cloudflare and Render. All connect to GitHub and redeploy each time you push. All have a free tier that runs a small app. Pick one and stop researching; changing later takes an afternoon.\n\nYour database is separate from your app host. Neon, Supabase and PlanetScale all have free tiers. The database on your laptop is not the database in production, and this catches people: the tables you made locally do not exist in the new one until you run your migrations against it.\n\n## The dev server lies to you\n\nWhat you run locally is a development server. It is patient, forgiving, and configured for your convenience. Production is a build. Things that work in one and not the other:\n\n**Filename case.** Your Mac or Windows machine treats `BookingCard.tsx` and `bookingcard.tsx` as the same file. The Linux server that runs your app does not. An import with the wrong capitalisation works locally and fails in production with \"module not found.\"\n\n**Environment variables.** Your `.env` file never left your laptop, on purpose. Every value in it (database URL, API keys) has to be entered again in the host's settings panel. This is the single most common deployment failure.\n\n**Hardcoded localhost.** A `fetch(\"http://localhost:3000/api/...\")` sitting somewhere in the code. Fine on your machine, dead everywhere else.\n\n**Dependencies in the wrong list.** A package installed as a dev dependency that the running app actually needs. The build cannot find it.\n\n**Type and lint errors.** Dev servers often run through them. Production builds usually stop.\n\nSo deploy early, on day two, with an app that barely does anything. A deploy failure on a tiny app is a ten-minute puzzle. The same failure on a big app after three weeks is a bad day.\n\n## The stranger is not you\n\nOnce it is live, the first real test is a person who is not you. They arrive with no cookies, no session, no seeded data, on a phone, possibly on a slow connection, and they click in an order you did not imagine.\n\nBefore you send the link:\n\n- Open the site in a private browsing window. Logged out, empty state. Does it make sense, or is it a blank screen because it assumed you had data?\n- Open it on your phone. Actually on your phone, not a narrow browser window.\n- Sign up as a brand new user, all the way through. This path is the least tested and the most important.\n- Try one thing wrong. Wrong password. Empty form. Refresh mid-way.\n- Press the browser back button after doing something. This breaks more AI-built apps than any other single action.\n\n## Watch what happens next\n\nOnce strangers are using it, you need two things you probably do not have yet.\n\n**Logs.** Every host has a page showing errors from the running app. Find it now, while nothing is wrong, so you know where to look when something is. A user saying \"it didn't work\" plus a log entry from that minute is a solvable problem. Either one alone is not.\n\n**A way to be told.** Something like Sentry, free at small volume, emails you when your app throws an error. Without it your error reporting is people bothering to complain, and most will not.\n\n## One more thing\n\nAdd a way for people to reach you: an email address in the footer is enough. The first stranger who hits a bug will otherwise leave silently, and you will never know the bug exists."},"check":{"question":"An app works perfectly at localhost:3000. Deployed, the pages load but every action that touches data returns a server error. What is the most likely cause?","options":[{"text":"The database has to be deployed alongside the code, and only the app was pushed.","correct":false,"tempting":"Imagines the database ships with the codebase, when it is a separate service the app connects to over the network."},{"text":"The host has no database connection string, because the .env file with it never left the laptop.","correct":true},{"text":"The production site runs on HTTPS while the code makes plain HTTP requests, which the browser blocks.","correct":false,"tempting":"Names a real class of production-only failure, but mixed content blocks browser requests rather than producing server errors on data operations."},{"text":"The free tier limits how many database connections an app is allowed to open.","correct":false,"tempting":"Blames the plan's limits, which is plausible under load but would not fail every request from the first visitor onward."}]},"prev":{"slug":"letting-the-agent-use-git","title":"Letting the agent use git, within limits","url":"https://addaly.com/learn/building-apps-with-ai/letting-the-agent-use-git"},"next":{"slug":"environment-variables-and-the-two-worlds","title":"Environment variables, and the prefix that leaks","url":"https://addaly.com/learn/building-apps-with-ai/environment-variables-and-the-two-worlds"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Deploying so a stranger can open it', in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/deploying-for-a-stranger (Accessed: 31 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Deploying so a stranger can open it","courseTitle":"Building Apps with AI","module":{"index":5,"slug":"save-points-and-shipping","title":"Save points, and shipping to a stranger"},"answer":null,"keyIdea":"Production differs from your laptop in configuration, case sensitivity and users, so deploy on day two, not week three.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"localhost-is-not-the-internet","runs":[{"text":"localhost is not the internet"}]},{"t":"p","runs":[{"text":"http://localhost:3000","code":true},{"text":" means “this computer.” Sending that link to a friend sends them to their own machine, where nothing is listening. This trips up everyone once."}]},{"t":"p","runs":[{"text":"To put your app somewhere a stranger can reach it, four things have to exist away from your laptop: your code, a machine to run it, your configuration, and your data."}]},{"t":"h2","id":"where-it-can-live","runs":[{"text":"Where it can live"}]},{"t":"p","runs":[{"text":"If you built on Replit, Lovable or Bolt, there is a deploy button and the platform handles all four. Use it. The rest of this lesson still matters, because the differences below still apply."}]},{"t":"p","runs":[{"text":"If you have your own repository, the common hosts are Vercel, Netlify, Cloudflare and Render. All connect to GitHub and redeploy each time you push. All have a free tier that runs a small app. Pick one and stop researching; changing later takes an afternoon."}]},{"t":"p","runs":[{"text":"Your database is separate from your app host. Neon, Supabase and PlanetScale all have free tiers. The database on your laptop is not the database in production, and this catches people: the tables you made locally do not exist in the new one until you run your migrations against it."}]},{"t":"h2","id":"the-dev-server-lies-to-you","runs":[{"text":"The dev server lies to you"}]},{"t":"p","runs":[{"text":"What you run locally is a development server. It is patient, forgiving, and configured for your convenience. Production is a build. Things that work in one and not the other:"}]},{"t":"p","runs":[{"text":"Filename case.","b":true},{"text":" Your Mac or Windows machine treats "},{"text":"BookingCard.tsx","code":true},{"text":" and "},{"text":"bookingcard.tsx","code":true},{"text":" as the same file. The Linux server that runs your app does not. An import with the wrong capitalisation works locally and fails in production with “module not found.”"}]},{"t":"p","runs":[{"text":"Environment variables.","b":true},{"text":" Your "},{"text":".env","code":true},{"text":" file never left your laptop, on purpose. Every value in it (database URL, API keys) has to be entered again in the host’s settings panel. This is the single most common deployment failure."}]},{"t":"p","runs":[{"text":"Hardcoded localhost.","b":true},{"text":" A "},{"text":"fetch(\"http://localhost:3000/api/...\")","code":true},{"text":" sitting somewhere in the code. Fine on your machine, dead everywhere else."}]},{"t":"p","runs":[{"text":"Dependencies in the wrong list.","b":true},{"text":" A package installed as a dev dependency that the running app actually needs. The build cannot find it."}]},{"t":"p","runs":[{"text":"Type and lint errors.","b":true},{"text":" Dev servers often run through them. Production builds usually stop."}]},{"t":"p","runs":[{"text":"So deploy early, on day two, with an app that barely does anything. A deploy failure on a tiny app is a ten-minute puzzle. The same failure on a big app after three weeks is a bad day."}]},{"t":"h2","id":"the-stranger-is-not-you","runs":[{"text":"The stranger is not you"}]},{"t":"p","runs":[{"text":"Once it is live, the first real test is a person who is not you. They arrive with no cookies, no session, no seeded data, on a phone, possibly on a slow connection, and they click in an order you did not imagine."}]},{"t":"p","runs":[{"text":"Before you send the link:"}]},{"t":"ul","items":[[{"text":"Open the site in a private browsing window. Logged out, empty state. Does it make sense, or is it a blank screen because it assumed you had data?"}],[{"text":"Open it on your phone. Actually on your phone, not a narrow browser window."}],[{"text":"Sign up as a brand new user, all the way through. This path is the least tested and the most important."}],[{"text":"Try one thing wrong. Wrong password. Empty form. Refresh mid-way."}],[{"text":"Press the browser back button after doing something. This breaks more AI-built apps than any other single action."}]]},{"t":"h2","id":"watch-what-happens-next","runs":[{"text":"Watch what happens next"}]},{"t":"p","runs":[{"text":"Once strangers are using it, you need two things you probably do not have yet."}]},{"t":"p","runs":[{"text":"Logs.","b":true},{"text":" Every host has a page showing errors from the running app. Find it now, while nothing is wrong, so you know where to look when something is. A user saying “it didn’t work” plus a log entry from that minute is a solvable problem. Either one alone is not."}]},{"t":"p","runs":[{"text":"A way to be told.","b":true},{"text":" Something like Sentry, free at small volume, emails you when your app throws an error. Without it your error reporting is people bothering to complain, and most will not."}]},{"t":"h2","id":"one-more-thing","runs":[{"text":"One more thing"}]},{"t":"p","runs":[{"text":"Add a way for people to reach you: an email address in the footer is enough. The first stranger who hits a bug will otherwise leave silently, and you will never know the bug exists."}]}],"check":{"question":[{"text":"An app works perfectly at localhost:3000. Deployed, the pages load but every action that touches data returns a server error. What is the most likely cause?"}],"options":[{"text":[{"text":"The database has to be deployed alongside the code, and only the app was pushed."}],"correct":false,"tempting":[{"text":"Imagines the database ships with the codebase, when it is a separate service the app connects to over the network."}]},{"text":[{"text":"The host has no database connection string, because the .env file with it never left the laptop."}],"correct":true,"tempting":null},{"text":[{"text":"The production site runs on HTTPS while the code makes plain HTTP requests, which the browser blocks."}],"correct":false,"tempting":[{"text":"Names a real class of production-only failure, but mixed content blocks browser requests rather than producing server errors on data operations."}]},{"text":[{"text":"The free tier limits how many database connections an app is allowed to open."}],"correct":false,"tempting":[{"text":"Blames the plan’s limits, which is plausible under load but would not fail every request from the first visitor onward."}]}],"order":[3,1,0,2],"why":null},"prev":{"slug":"letting-the-agent-use-git","title":"Letting the agent use git, within limits","minutes":8},"next":{"slug":"environment-variables-and-the-two-worlds","title":"Environment variables, and the prefix that leaks","minutes":9}}}