Skip to content

Lesson 1 — Introduction to Deployment & Cloud Hosting ​

In this lesson, you will take your first applications from running on your computer to being accessible on the internet.

You will learn the vocabulary of deployment, understand why software teams use different environments, and compare hosting models. Then you will publish two small projects:

  • A static website on Netlify.
  • A Node.js/Express API on Render.

These two examples illustrate an important idea: the way you deploy an application depends on what the application needs to run.

Your project throughout the course

Keep the Node.js API you build here. In later lessons, you will add automated tests with Vitest, package it with Docker, connect it to MySQL, and automate its deployment.

DigitalOcean will be introduced in the later cloud-deployment lesson. You do not need to set up a server or a DigitalOcean account now.

Learning outcomes ​

By the end of this lesson, you should be able to:

  1. Explain deployment, hosting, builds, environments, and releases in your own words.
  2. Differentiate between development, staging, and production environments.
  3. Choose between static hosting, a managed application platform, and a virtual private server (VPS) based on application requirements.
  4. Deploy a static HTML page to Netlify and a Node.js/Express API to Render.
  5. Verify that both applications are available publicly and identify basic deployment problems.
  6. Describe manual, automated, rolling, and blue-green deployment approaches, including why rollbacks matter.

What you need ​

You should be familiar with basic JavaScript, terminal commands, and Git. You do not need prior cloud deployment experience.

Tool or accountWhy you need it
Node.js (LTS) and npmRun the backend locally and install its dependencies
Git and GitHubVersion the API and make its source available to Render
A code editor and a terminalCreate and edit project files
A Netlify accountPublish a static website
A Render accountDeploy an Express API as a managed web service
A browser or curlTest the deployed applications

Accounts and costs

Hosting plans, included usage, and account requirements can change. Review the current options before creating services. You do not need a paid plan specifically for the examples in this lesson if a suitable free option is available to your account. Some free services have limitations; we will point out relevant ones as we go.

What you will build ​

text
Your computer
│
├── site/index.html ────────────────→ Netlify
│                                      Static website
│                                      Public .netlify.app URL
│
└── src/server.js + package.json ──→ GitHub ──→ Render
                                                   Express API
                                                   Public .onrender.com URL

At the end, you should have two public URLs that you can open from another device.


Part 1 — Understanding Deployment ​

1. What is deployment? ​

Deployment means making a particular version of an application available in a target environment.

For a static website, deployment might mean uploading HTML, CSS, and JavaScript files to a hosting platform. For a backend, it might mean installing dependencies, starting a Node.js process, and making it reachable over HTTPS.

A deployment usually involves more than simply copying code. Think about these questions:

  • Where does the application run? On a managed platform or a server you operate?
  • What does it need? A Node.js runtime, dependencies, or a database?
  • How does it start? For example, with npm start?
  • How is it configured? Through environment variables and platform settings?
  • How do you know it works? With a browser request, an API endpoint, or health checks?
  • What if something goes wrong? Can you inspect logs and return to a previous version?

A typical deployment process looks like this:

text
Write code → Test → Prepare/build → Deploy → Verify → Monitor

Deployment vs. release

A deployment puts code into an environment. A release makes functionality available to users. They often happen together, but a team can deploy a feature and keep it disabled until a later release.

2. Important terminology ​

TermMeaning
HostingProviding the infrastructure or platform where an application runs
ServerA computer or service that responds to requests
RuntimeSoftware needed to execute code, such as Node.js
BuildA process that prepares application files for execution or publication; not every application needs one
ArtifactA deployable output, such as built static files or a Docker image
EnvironmentA configured place where a version of an application runs
Environment variableConfiguration supplied to a process without hardcoding it in source files
Domain / URLAn address used to access the deployed application
DowntimeA period when an application is unavailable
RollbackReturning to a previously working version or state
CI/CDPractices for automating integration, delivery, and deployment; explored in Lesson 2

Local is not public ​

If you start an API at:

text
http://localhost:3000

it can usually be reached only from your own computer. The word localhost refers to the computer making the request.

After deployment, your API can receive a publicly accessible URL, for example:

text
https://your-api-name.onrender.com

The example address above is not your URL. Render will provide the actual one after you deploy.

3. Development, staging, and production ​

These environments allow teams to test changes before they affect real users.

EnvironmentWhat it is forExample
DevelopmentBuilding features and debugging codeRunning Express on your laptop
StagingChecking a release in a production-like setupTesting a candidate version before going live
ProductionServing real usersYour live Netlify site or Render API
text
Development → Staging → Production
  Build         Validate      Serve users

A small learning project may begin with only local development and a public deployment. Larger projects often introduce staging to reduce release risk.

A useful staging environment resembles production in important ways, but it should not expose production credentials or sensitive customer information.

Check your understanding ​

Which environment is the best fit for each activity?

  1. Trying a new endpoint that you expect to change repeatedly.
  2. Validating a version before customers see it.
  3. Serving requests from real customers.
  4. Reproducing a configuration issue before a release.
Reveal suggested answers
  1. Development.
  2. Staging.
  3. Production.
  4. Staging, ideally with relevant production-like configuration.

Part 2 — Choosing Where to Deploy ​

4. Common hosting models ​

Static hosting ​

Static hosting serves files such as HTML, CSS, images, and browser JavaScript. It does not require you to run a continuously listening Node.js server.

Example: a personal website, portfolio, or documentation site published on Netlify.

Platform as a Service (PaaS) ​

A managed application platform runs your application without requiring you to administer the underlying operating system. You typically connect a repository, set build and start commands, and configure your service.

Example: an Express API deployed as a Render Web Service.

Virtual private server (VPS) ​

A VPS gives you a virtual machine. You can install Node.js, Docker, MySQL, and other software yourself, but you are also responsible for maintaining the server and securing its configuration.

Example: a Linux virtual server. We will explore this approach with DigitalOcean later in the course.

5. Netlify vs. Render ​

For the practical work in this lesson, each platform has a specific job.

QuestionNetlify (our static site)Render (our API)
What are we deploying?HTML/CSS filesA running Node.js/Express server
Does our example need a Node.js server running continuously?NoYes, when handling requests
Where does the application code come from?A local folder uploaded manuallyA GitHub repository
How will we test it?Open the website URLRequest / and /health
What will we learn?Publishing static filesRunning backend applications on a managed platform

Netlify can also run functions, and Render can also host static sites. We are choosing these two paths because they make the difference between static hosting and backend hosting easy to see.

Choose the hosting model ​

Which option is a good starting point for each project?

ProjectConsider the requirements
A landing page made of HTML and CSSNo server-side logic
A Node.js REST APINeeds a runtime and a listening process
An application whose team must install and configure its own services on LinuxNeeds direct server control
Reveal possible answers
  • Landing page: static hosting such as Netlify.
  • Node.js REST API: a managed web service such as Render.
  • Full Linux control: a VPS, such as a DigitalOcean Droplet (covered later).

These are examples, not exclusive rules. The right answer depends on the application and operational requirements.


Part 3 — Practical Example: Deploy a Static Site to Netlify ​

In this first deployment, you will publish a single HTML page. No backend or build step is required.

6. Create the project ​

Open a terminal and create a project directory:

bash
mkdir deployment-workshop
cd deployment-workshop
mkdir site

Create site/index.html with this content:

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>My First Deployment</title>
    <style>
      body {
        font-family: system-ui, sans-serif;
        max-width: 640px;
        margin: 4rem auto;
        padding: 0 1rem;
        line-height: 1.6;
      }
      h1 { color: #186b57; }
    </style>
  </head>
  <body>
    <h1>Hello from Netlify!</h1>
    <p>This is my first publicly deployed website.</p>
    <p>I deployed it by publishing a folder of static files.</p>
  </body>
</html>

Open site/index.html in your browser to check it locally.

Why is there no npm start?

This page is just HTML and CSS. Your browser can display it directly, and Netlify can serve the same files without running an Express application.

7. Publish the site on Netlify ​

  1. Sign in to Netlify.
  2. Open Netlify Drop, or choose the dashboard option to add a project by dragging and dropping files.
  3. Upload the site folder, not the entire deployment-workshop folder. The uploaded folder must have index.html at its top level.
  4. Open the site URL that Netlify provides.
  5. Verify that the heading “Hello from Netlify!” is visible.

Your page should now be available at an address similar to:

text
https://your-site-name.netlify.app

Make a change and redeploy ​

Update the text in site/index.html, save the file, and upload the updated site folder to your existing Netlify project using its deploy interface.

Refresh the public page to confirm that your change is visible.

What did you just do?

You performed a manual deployment: you explicitly selected files and published them. Later, you will see how connecting a repository lets a hosting platform deploy changes automatically.

Common Netlify problems ​

ProblemWhat to check
Page not foundDid you upload the folder containing index.html, rather than its parent?
The old page is still shownDid you deploy the updated folder to the same project? Try refreshing the page.
HTML file downloads or renders unexpectedlyCheck that the file is actually named index.html and contains valid HTML.

Your Netlify checkpoint ​

  • [ ] My website works locally.
  • [ ] I can open it using my Netlify URL.
  • [ ] I published an updated version successfully.
  • [ ] I can explain why this page does not need a continuously running backend.

Part 4 — Practical Example: Deploy a Node.js API to Render ​

Next, you will deploy a backend. Unlike the static page, this application needs Node.js to run server-side code when requests arrive.

You will keep this API for the following lessons.

8. Set up an Express application ​

Return to your existing project directory:

bash
cd deployment-workshop
npm init -y
npm install express
npm pkg set type=module
npm pkg set scripts.start="node src/server.js"
npm pkg set scripts.dev="node --watch src/server.js"
mkdir src

Already inside the project?

If your terminal is already in deployment-workshop, do not run the cd deployment-workshop line again.

Create src/server.js:

js
import express from 'express';

const app = express();
const port = Number(process.env.PORT || 3000);

app.use(express.json());

app.get('/', (_req, res) => {
  res.json({ message: 'Hello from Render!' });
});

app.get('/health', (_req, res) => {
  res.status(200).json({ status: 'ok' });
});

app.listen(port, '0.0.0.0', () => {
  console.log(`API listening on port ${port}`);
});

Three details matter here:

  • process.env.PORT allows the hosting environment to configure the port. You should not hardcode a production port.
  • 0.0.0.0 lets the application listen on the container or server network interface rather than only the loopback interface.
  • /health gives you a basic endpoint for checking whether the API process is responding.

9. Test the API locally ​

Start the application:

bash
npm start

Visit these URLs in a browser, or run the following commands in another terminal:

bash
curl http://localhost:3000/
curl http://localhost:3000/health

Expected responses:

json
{"message":"Hello from Render!"}
json
{"status":"ok"}

Stop the local server with Ctrl+C after testing.

10. Prepare your Git repository ​

Create .gitignore in the project root:

text
node_modules/
.env
.env.*
!.env.example
coverage/
.DS_Store

Create .env.example to document local configuration:

dotenv
PORT=3000
NODE_ENV=development

Never commit secrets

Never commit actual .env files, passwords, API keys, or database credentials. The .env.example file only documents possible settings; our current server does not load it automatically. You will learn more about environment configuration in Lesson 4.

Your folder structure should now look like this:

text
deployment-workshop/
├── site/
│   └── index.html
├── src/
│   └── server.js
├── .env.example
├── .gitignore
├── package.json
└── package-lock.json

If this is a new Git project, initialize it and commit your work:

bash
git init
git add .
git commit -m "Add static site and Express API"
git branch -M main

Create an empty GitHub repository called deployment-workshop (do not initialize it with a README). Connect it using your own repository URL:

bash
git remote add origin https://github.com/YOUR_USERNAME/deployment-workshop.git
git push -u origin main

Replace YOUR_USERNAME with your GitHub username. GitHub may ask you to authenticate; follow its instructions. If your repository already has a remote, use that remote instead of adding another.

11. Deploy the API on Render ​

  1. Sign in to Render.
  2. Select New → Web Service.
  3. Connect your GitHub account and select the deployment-workshop repository.
  4. Configure the service with the values below.
  5. Review the available instance plans and choose one suitable for learning.
  6. Create the service and inspect its deployment output.
SettingValue
Service typeWeb Service
Language / runtimeNode
RepositoryYour deployment-workshop repository
Branchmain
Root directoryRepository root (. or the default)
Build commandnpm ci
Start commandnpm start

You do not need to set a custom PORT value for this example; Render supplies the appropriate port setting. The npm ci command uses the committed package-lock.json to install dependencies reproducibly.

When deployment succeeds, Render provides a URL similar to:

text
https://your-api-name.onrender.com

Free instance behavior

If you select Render's Free web service plan, the service may spin down after a period of inactivity. The next request can take longer while it starts again. That delay does not automatically mean your code is broken. Check Render's current plan documentation for details.

12. Verify the public API ​

Replace YOUR_RENDER_URL below with the public URL shown in your Render dashboard:

bash
curl https://YOUR_RENDER_URL/health

Expected response:

json
{"status":"ok"}

Also open the root URL to check the greeting:

json
{"message":"Hello from Render!"}

Try opening the same /health URL on another device. This demonstrates the difference between localhost and a public deployment.

Update the API and observe deployment behavior ​

Change the / response message in src/server.js. Commit and push:

bash
git add src/server.js
git commit -m "Update API greeting"
git push

Return to Render and inspect your service's deployment activity. A Git-connected Render service normally starts a new deployment after changes are pushed to the linked branch, when automatic deployment is enabled.

Once the deployment succeeds, request the root URL again to see the new message.

Compare the two workflows:

  • With Netlify Drop, you published files manually.
  • With your Git-connected Render service, you pushed code and the platform performed the deployment steps.

Git-connected deployment is useful, but it is not the same as a fully tested CI/CD pipeline. In Lesson 2, you will add automated tests using Vitest and GitHub Actions.

Common Render problems ​

ProblemWhat to check
Build failedConfirm that package.json and package-lock.json are committed, and inspect the build logs.
Service did not startConfirm the start command is npm start and the script runs locally.
Service cannot be reachedCheck the deploy status, the public URL, and the app's listening port.
/health returns 404Confirm the route exists and that you deployed the latest commit.
First request takes a whileA free service might be waking up after inactivity.

Your Render checkpoint ​

  • [ ] npm start works locally.
  • [ ] My API source code is in GitHub.
  • [ ] Render reports a successful deployment.
  • [ ] The public /health endpoint returns {"status":"ok"}.
  • [ ] I pushed a change and observed a new deployment.

Part 5 — Deployment Strategies and Recovery ​

13. Manual vs. automated deployment ​

You have now seen two ways to publish code:

  • Manual deployment: you selected and uploaded the static files to Netlify.
  • Platform-triggered deployment: you pushed a Git commit and Render deployed the linked branch.

A more complete automated pipeline might look like this:

text
Push code → Run tests → Build → Deploy → Verify

We will construct this sort of workflow during the course. Automation makes a process more repeatable, but it does not replace testing, security reviews, or monitoring.

14. How can new versions replace old versions? ​

Recreate (stop and replace) ​

text
Version A → stop → start Version B

Simple to understand, but the application may be briefly unavailable.

Rolling deployment ​

text
[A] [A] [A]
[B] [A] [A]
[B] [B] [A]
[B] [B] [B]

Instances are replaced gradually. This can reduce downtime, but requires enough capacity and compatibility between versions.

Blue-green deployment ​

text
Before: users → Blue (A)      Green (B) ready
After:  users → Green (B)     Blue (A) retained temporarily

Two environments are prepared, and traffic is switched to the new one after validation. This can make reverting application traffic easier, but adds infrastructure and configuration complexity.

Rollback ​

A rollback returns an application to a previously working version or state. Before deploying a change, ask yourself:

  1. Which version worked before this change?
  2. Can I deploy it again?
  3. How will I confirm that recovery succeeded?
  4. Could a database change make returning to the old version unsafe?

Rollbacks and databases

Reverting application code does not automatically restore database schemas or data. You will explore MySQL migrations, backups, and restoration in later lessons.

Think about this ​

You changed the Express API response and deployed the new version on Render, but the public endpoint now returns an error. What would you check first? What would you do if you could not fix it quickly?

Suggested approach

First inspect Render's deployment status and logs, verify the configured start command, and check whether the expected code was deployed. If the problem affects users and cannot be resolved safely, use an available rollback or redeploy a known working commit, then verify /health and the API response.


Final Exercise — Explain Your Deployments ​

Complete the table using the actual URLs from your accounts.

QuestionYour answer
What is your Netlify website URL?Add your URL
What files did Netlify publish?Your answer
What is your Render API URL?Add your URL
What command starts your Express API?Your answer
Which of your deployments required a running Node.js server?Your answer
How did you publish an update to Netlify?Your answer
How did you publish an update to Render?Your answer

Add a link to your Netlify page that opens your Render API's /health endpoint:

html
<a href="https://YOUR_RENDER_URL/health" target="_blank" rel="noopener noreferrer">
  View my API health check
</a>

Replace the example URL with your own, then manually redeploy the updated site folder to Netlify.

This is only a link to the API, so no cross-origin browser API request is needed. You will learn how to build more complex integrations later.


Knowledge Check ​

Try answering these questions before revealing the answers.

  1. What is the difference between deployment and release?
  2. Why is localhost not a suitable public API URL?
  3. What is the purpose of staging?
  4. Why is static hosting a good fit for the HTML page?
  5. Why does our Express API need a backend hosting service?
  6. What do Render's build and start commands do?
  7. What was manual about the Netlify deployment?
  8. What event triggered a new Render deployment?
  9. How does a rolling deployment differ from a blue-green deployment?
  10. What should you verify after a deployment or rollback?
Reveal suggested answers
  1. Deployment installs or publishes a version; release makes functionality available to users.
  2. localhost points to the machine making the request, not your publicly accessible host.
  3. Staging lets you verify changes in a production-like environment before users are affected.
  4. The browser only needs static files; no continuously running backend is required.
  5. Express handles HTTP requests in a running Node.js process.
  6. The build command prepares dependencies or build output; the start command launches the application.
  7. You explicitly uploaded the folder and then repeated the upload to publish a change.
  8. A push to the linked Git branch, when automatic deployment was enabled.
  9. Rolling deployment replaces instances incrementally; blue-green switches traffic between separately prepared environments.
  10. Confirm the service is available and that important routes and behaviors work as expected.

Summary ​

You deployed two different types of application:

  • A static website to Netlify, by publishing a folder of HTML files.
  • A Node.js/Express API to Render, by connecting a GitHub repository and configuring a web service.

You also learned that development, staging, and production environments serve different purposes, and that deployment strategies affect how safely new versions reach users.

The key takeaway is this: deploying a static site is different from deploying a backend because their runtime requirements are different.

Before Lesson 2 ​

  • [ ] Keep the deployment-workshop project on your computer.
  • [ ] Make sure the Express API is committed and pushed to GitHub.
  • [ ] Check that both your Netlify website and Render API URLs still work.
  • [ ] Be ready to explain the difference between a manual deployment and a Git-triggered deployment.

Next: Lesson 2 — Continuous Integration & Continuous Deployment (CI/CD). You will add Vitest tests and create a GitHub Actions workflow for your API.

Further reading ​