JOUR 73361

Coding the News

Learn how America's top news organizations escape rigid publishing systems to design beautiful data-driven stories on deadline.

Ben Welsh, Adjunct Assistant Professor

Spring 2026

Mondays 6–9 p.m.

Lab 436

Static-Site Frameworks

How to publish a website with Node.JS and GitHub Actions

Feb. 2, 2026

Part 1: Introduction to Frameworks

What's a framework? Nothing more than a fancy name for a set of software tools that can create and publish a website.

It takes dozens of different software tricks to pull a good site together. Frameworks aim to make the challenge easier by curating a set of time-saving tools that can work in harmony.

There are a lot of different frameworks out there. Maybe you've heard of some of them, like React, Next.js, Svelte, Django, or Ruby on Rails.

Each newsroom tends to go its own way, picking and choosing among the most popular tools. While the programming languages and the details vary from shop to shop, the fundamentals are almost all the same.

Many newsroom frameworks are published as open source software, including templates you can use to get started quickly.

Newsroom Frameworks
https://github.com
Animated showcase of newsroom framework repositories on GitHub, cycling through Reuters graphics-kit, LA Times baker, The Pudding svelte-starter, The City react-template, Texas Tribune data-visuals-create, Seattle Times newsapp-template, and NPR dailygraphics

Examples include:

While they were developed separately, they all have two things in common.

One, they follow a web development approach known as static-site generation. This means that, regardless of what tools they use, they ultimately build a set of static HTML, CSS, and JavaScript files that can be served by any web server. That's unlike dynamic sites that generate pages on the fly using server-side code and databases, like WordPress or Drupal.

It's a popular development pattern for simple sites, and it dominates newsroom projects. Static sites are cheaper, more secure, more stable and easier to archive than sites that rely on dy­nam­ic systems.

Two, they all use the Node.js programming system, which will be the first thing we need to install.

Part 2: Introduction to Node.js

Node.js is a system that lets you run JavaScript, the programming language of the web, on your computer, not just in a web browser. It's the engine that powers most modern web development tools, including all of the newsroom frameworks we just discussed.

Node.js
https://nodejs.org
Node.js homepage showing download options

Its massive ecosystem of open-source packages, accessible via the Node Package Manager, provides developers with a vast array of tools to build applications. Those tools include static-site frameworks invented and supported by major tech companies, as well as countless smaller projects maintained by individual developers.

You can learn more about it at nodejs.org.

Check if Node.js is already installed

Before we install anything, let's check if you already have Node.js on your computer. Some of you may have installed it for another class or project.

Open Visual Studio Code. If you don't have a project open, that's fine. Click Terminal in the menu bar and select New Terminal.

Type this command and press Enter:

node --version

If Node.js is installed, you'll see a version number like v20.11.0 or similar. If you see a version starting with v18, v20, or higher, you're all set! You can skip ahead to Part 3.

If you see an error message like command not found: node, that means Node.js isn't installed yet.

We'll fix that with a tool called Node Version Manager.

Install nvm

Node Version Manager, also known as nvm, is a command-line tool that makes it easy to install and manage multiple versions of Node.js on your computer. It's especially useful for developers who need to switch between different Node.js versions for different projects.

nvm
https://www.nvmnode.com
Node Version Manager homepage showing installation instructions

Before we can use it to install Node.js, we need to install nvm itself.

Copy and paste this command into your terminal and press Enter:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

This downloads and runs the official nvm installation script. You'll see some output as it installs. It should look something like:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 16774  100 16774    0     0  45969      0 --:--:-- --:--:-- --:--:-- 45956
=> Downloading nvm from git to '/Users/U6122976/.nvm'
=> Cloning into '/Users/U6122976/.nvm'...
remote: Enumerating objects: 403, done.
remote: Counting objects: 100% (403/403), done.
remote: Compressing objects: 100% (332/332), done.
remote: Total 403 (delta 56), reused 168 (delta 43), pack-reused 0 (from 0)
Receiving objects: 100% (403/403), 404.19 KiB | 2.41 MiB/s, done.
Resolving deltas: 100% (56/56), done.
* (HEAD detached at FETCH_HEAD)
  master
=> Compressing and cleaning up git repository

=> Appending nvm source string to /Users/U6122976/.zshrc
=> Appending bash_completion source string to /Users/U6122976/.zshrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

At the very bottom there, you'll see a message about adding nvm to your terminal's configuration file. In my case, it's called the .zshrc file, because I'm using the Z shell terminal program. Yours might be called .bashrc or .bash_profile if you're using Bash, or another name if you're using a different terminal program.

This is important, because it is how nvm is booted up whenever you open a terminal. And it won't take effect until you restart your terminal, so do that now before you proceed.

In the new terminal you should verify nvm is installed by typing:

nvm --version

You should see a version number like 0.40.4. Now you're ready to install Node.js.

Install Node.js with nvm

Now we can use nvm to install Node.js by typing this command:

nvm install --lts

The --lts option tells nvm to install the "Long Term Support" version of Node.js. This is the stable, recommended version for most users. You'll see progress as it downloads and installs. It should look something like this:

Installing latest LTS version.
Downloading and installing node v24.13.0...
Downloading https://nodejs.org/dist/v24.13.0/node-v24.13.0-darwin-arm64.tar.xz...
################################################################################# 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v24.13.0 (npm v11.6.2)
Creating default alias: default -> lts/* (-> v24.13.0 *)

Let's confirm everything worked by running the same command as before:

node --version

You should now see a version number like v24.13.0, or whatever the current LTS version is.

You should also check that the Node Package Manager was installed alongside Node.js, which is the tool we'll use to install additional packages.

npm --version

You should see a version number like 11.6.2.

You now have Node.js installed and ready to use. This is the foundation that will power all the web development tools we'll use throughout the rest of this course.

Part 3: Creating a page from a static-site template

Now that you have Node.js installed, let's put it to work. We're going to use a GitHub template I've created for this class. It's a minimal framework configured to build static websites in the style of CUNY's NYCity News Service.

CUNY Static Site Template
https://palewire.github.io/cuny-jour-static-site-template/
Animated preview of the CUNY static site template showing a sample news story layout with hero image

Create a new repository from the template

Open your browser and navigate to github.com/palewire/cuny-jour-static-site-template.

cuny-jour-static-site-template
https://github.com/palewire/cuny-jour-static-site-template
GitHub template repository page showing the Use this template button

Click the green "Use this template" button near the top right of the page. Select "Create a new repository" from the dropdown menu. You'll be taken to a page where you can name your new repository.

Create a new repository
https://github.com/new
GitHub Create a new repository form with my-first-static-site as the name

Select your account as the owner. Enter my-first-static-site as the repository name. Make sure "Public" is selected in the visibility options. Then click the green "Create repository" button.

After a moment, you'll be redirected to your new repository's page.

my-first-static-site
https://github.com/yourusername/my-first-static-site
GitHub page showing the newly created my-first-static-site repository

Clone the repository to your computer

Now let's get this code onto your computer using the techniques we covered in week one.

Open a new window in Visual Studio Code. Click on the "Source Control" icon in the left sidebar, the one that looks like a Y or a branch, and click the "Clone Repository" button.

A popup will appear at the top of the window asking for a repository URL. Go back to your browser, copy the URL to your new repository and paste it into the popup. Press enter.

A file dialog will open asking where to save the project. Navigate to your Code folder we made last week and click "Select Repository Location." After a few moments, VS Code will ask if you want to open the cloned repository. Click "Open."

You should now see the project files in the Explorer sidebar. Take a moment to look around. You'll see folders like src and static, and files like package.json and svelte.config.js.

Visual Studio Code Explorer showing the template project structure

Install the project dependencies

Before we can run the project, we need to install its dependencies. These are external packages of code that the project needs to work. They're listed in the package.json file.

Visual Studio Code showing package.json file with project dependencies

Open a terminal in VS Code by clicking "Terminal" in the menu bar and selecting "New Terminal". Type the following command and press Enter:

npm install

This tells Node Package Manager to read the package.json file and download all the packages listed there. You'll see a progress indicator as packages are downloaded. This may take a minute or two the first time.

When it's done, you'll see a summary of what was installed.

Terminal showing npm install complete with node_modules folder visible

You'll notice a new node_modules folder has appeared in the Explorer. This contains all the downloaded packages. You don't need to look inside it and, in fact, it's best to ignore it entirely.

Another new file is called package-lock.json. This file locks the exact versions of the installed packages to ensure consistency across different environments. You also don't need to edit this file manually. It's for computers, not humans.

Start the development server

Now for the fun part. Type this command in the terminal:

npm run dev

This starts a local development server on your computer. After a moment, you'll see a message saying the server is running, with a URL like http://localhost:5173.

Terminal showing Vite dev server running at localhost:5173

Open your browser and navigate to that URL, http://localhost:5173. You should see the template homepage.

My Static Site
http://localhost:5173
Browser showing the template homepage at localhost:5173

Congratulations! You're running a local web server. Unlike the demonstration page we saw earlier, this page you see is being generated by the code in your project folder.

Make your first edit

Let's change something. In VS Code's Explorer sidebar, navigate to src/routes/+page.svelte and click to open it.

Visual Studio Code showing +page.svelte file content

This is the homepage of your site. There's a lot going on here. We'll cover it all in detail later. For now, just focus on the top part of the file, the part inside the script tags.

Find the line that says:

let headline = 'Become a force for good. Join our next class.';

Change it to something more personal, like:

let headline = 'Breaking News: This is my first static site!';

Save the file. Now look at your browser. Without refreshing, the page has automatically updated to show your new text!

Hello from CUNY
http://localhost:5173
Browser showing the updated homepage with 'Hello from CUNY'

Try making a few more changes. Edit the byline and publication date. Get a feel for how quickly you can see your changes reflected.

The project structure

We'll dig into more later, but let's pause briefly for an overview of the main files and folders in this project:

FilesDescription
src/routes/+page.svelteYour homepage. The +page.svelte file in any folder becomes a page on your site.
src/routes/+layout.svelteWraps every page. It's where you'd put headers, footers, or navigation that appears on all pages.
src/app.cssGlobal styles that apply to your entire site.
src/app.htmlThe HTML shell that wraps everything.
static/A folder for static files like images. Anything here is copied directly to your built site.
package.jsonLists your project's dependencies and scripts.
svelte.config.jsConfiguration for SvelteKit, including how to build your site.

You can ask Copilot to explain any of these files in more detail. Just open the file and ask in the chat panel, "What does this file do?"

Stop the development server

When you're done working, you can stop the development server by clicking in the terminal and pressing Ctrl + C. You'll see a message confirming the server has stopped.

You can restart it anytime by running npm run dev again.

Part 4: Publishing with GitHub Pages and Actions

You have a website running on your computer, but how do you share it with the world? That's where GitHub Pages comes in. It's a free hosting service that can publish static websites directly from any GitHub repository.

GitHub Pages
https://pages.github.com
GitHub Pages homepage showing 'Websites for you and your projects' tagline with a laptop displaying a sample project site

It might not sound like much, but this simple, generous service is used by developers to host a gigantic number of websites, ranging from personal portfolios and open-source documentation to highly sophisticated commercial sites.

I routinely use to publish hobby projects, like cummings.ee, moneyinpolitics.wtf and studs.show.

Hobby Sites
https://github.io
Animated showcase of hobby websites built with GitHub Pages: cummings.ee, moneyinpolitics.wtf, and studs.show

To take advantage of it, we need to tell GitHub to serve your repository as a website. Go to your my-first-static-site repository on GitHub in your browser.

Click on "Settings" in the top navigation bar and then select "Pages" from the left sidebar.

Settings - Pages
https://github.com/yourusername/my-first-static-site/settings/pages
GitHub repository Settings page showing Pages option in sidebar

Under "Source," you'll see a dropdown that likely says "Deploy from a branch." Click it and select GitHub Actions instead.

Settings - Pages
https://github.com/yourusername/my-first-static-site/settings/pages
GitHub Pages settings showing Source dropdown with GitHub Actions selected

That's it. GitHub will now look for a GitHub Actions workflow in your repository that builds and deploys your site whenever you push changes.

But, wait, what are GitHub Actions?

Introduction to GitHub Actions

GitHub Actions is a powerful automation platform built into GitHub. It allows you to create custom workflows that automate tasks like building, testing, and deploying code whenever certain events occur in your repository. It's yet another reason that GitHub is so popular.

GitHub Actions
https://github.com/features/actions
GitHub Actions homepage showing 'Automate your workflow from idea to production' with workflow automation features

We won't cover it in great detail in this class, but Actions is quickly becoming an essential tool in the data journalism toolbox. You can learn more about it in "Go big with GitHub Actions," an open-source textbook I developed with Iris Lee and Dana Chiueh.

Go big with GitHub Actions
https://palewi.re/docs/go-big-with-github-actions/
'Go big with GitHub Actions' tutorial homepage showing the course title and description

GitHub Actions are configured by workflow files stored in your repository's .github/workflows/ folder. Each workflow is written in the YAML format, which is yet another arcane way that humans like to boss computers around.

Open the .github/workflows/deploy.yml file in your project. This file defines a workflow that builds and deploys your static site to GitHub Pages whenever you push changes.

Visual Studio Code showing deploy.yml workflow file with GitHub Actions configuration

Commit and push your changes

That means all you have to do to publish your page is commit and push the changes you made earlier to +page.svelte.

In Visual Studio Code, open the "Source Control" panel we learned about last week. Commit your changes with a message like "Updated headline" and push them to GitHub.

Watch the workflow run

Go back to your repository on GitHub in your browser. Click on the "Actions" tab.

You should see a workflow run with your commit message as its title. It's running through the same steps you ran locally, installing dependencies and building the site, but on GitHub's servers. It will spin for a few minutes and then, if all goes well, resolve as a green check mark.

my-first-static-site - Actions
https://github.com/palewire/my-first-static-site/actions
GitHub repository page with Actions tab showing workflow runs

The first commit's run at the bottom of the list will likely have failed, because Pages wasn't set up yet. Don't worry about that one. Focus on the most recent run at the top of the list.

View your published site

Click into the most recent workflow run to see its details. The "Deploy" step should have a URL to your live site.

Deploy to GitHub Pages
https://github.com/palewire/my-first-static-site/actions/runs/21569912931
GitHub Actions workflow run details showing build and deploy jobs with green checkmarks

You can also figure out your URL on your own by following GitHub's standard Pages URL format:

https://<your-username>.github.io/<your-repo-name>/

Hit the link to visit your site. You should see the same page you were editing locally, now available to anyone on the internet.

My First Static Site
https://palewire.github.io/my-first-static-site/
The published static site live on GitHub Pages showing the edited headline

From now on, every time you push changes to your repository, GitHub Actions will automatically rebuild and redeploy your site. The whole process takes just a minute or two.

Homework Assignments

Task 1: Create three static sites

Create three different repositories using the class template. Each should have a different name and personalized content.

They don't have to do much. The point is to get practice. Swap out the image, rewrite the body text, change the byline to your own name, or whatever you like.

Deploy all three to GitHub Pages. Send me links to all three live sites before next Monday's class.

Task 2: Explore another newsroom's template

Find a static site template from a news organization and try to create a new project from it. Use Copilot to help you understand how it works and how to deploy it.

Don't spend more than an hour or two on it. It's okay if you fail. These tools are complex, and frequently undocumented. When you get stuck, ask Copilot for help.

Document your process in a README file. What worked? What didn't? What did you learn?

Task 3: Be prepared to present

Be ready to present one of your three static sites to the class and talk about your experience exploring another newsroom's template. What challenges did you face? What did you learn?