Intermediate guide to publish a Quarto website with GitHub & Netlify

R
Quarto
GitHub
Netlify
Learn how to publish a Quarto website, connect it to GitHub, & deploy it with Netlify using continuous integration.
Author

Jadey Ryan

Published

November 19, 2023

Thankfully, many amazing resources for building beautiful websites and blogs with Quarto already exist. Instead of adding to that pool of content, I’ll demo how I built my website with Quarto, connected to a GitHub repository, and then deployed and published with Netlify continuous deployment. Special thanks to Libby Heeren for testing this demo and helping me clarify some sticky points! ♥️

I struggled for hours trying to set up the configurations so my site would deploy every time I pushed a change to my GitHub repo. Hopefully this demo saves you some time when you start your own website! :)

As with most tech and dev stuff, there’s many ways to do (almost) the same thing. I’d love to hear how other people have their Quarto/Netlify workflows set up. Leave a comment at the end of the post, or reach out!

Anyhoo, keep on reading to learn about:

Why Netlify?

There are lots of options for publishing Quarto websites:

Honestly, I was completely overwhelmed by all the options. I had to think about what was most important to me:

  1. using my own custom domain
  2. continuous integration so I could deploy from version control
  3. easy configuration and maintenance

I checked out what other #RStats bloggers1 were using and found many folks used GitHub Pages or Netlify.

After some repo-diving and research, I decided to go with Netlify and their starter plan, shown below:

Netlify starter stats for my account. Bandwidth is 745 MB/100 GB. Build minutes is 43/300. Concurrent builds is 0/1. Team members is 1.

I don’t think I’ll ever get near the Netlify starter plan limits, but who knows. If I exceed the limits, I pay as I go. Or, I can upgrade to $19/month for much higher limits.

A major selling point for Netlify is the free deployment preview system. We can use branch deploys to preview changes from a feature branch or deploy previews to see changes from pull requests and merges. These deployment previews don’t touch our site in production.

Differences between deploy and publish

I was confused about the terminology of deploying and publishing a website. While they seem interchangeable, there are some subtle differences.

Deploys push files to Netlify’s server and build the site. We can have multiple deploys with their own unique URLs that we use to preview changes. These represent our site at specific points in time and are useful for testing or staging.

Publishing makes the deployed site publicly available at our main URL. This published site is what I’ll call our site in production, meaning it’s live and accessible to users.

A similar feature is under development for GitHub Pages, according to this discussion on GitHub Community.

Jump to the Branch deploys and deploy previews section for more details on the deployment preview system.

Important Note about Continuous Integration (CI)

Netlify servers can render markdown and build the website2, but cannot execute code3. This means all code must be executed locally on our computer and the output must be saved via the Quarto freeze feature AND committed to our repo.4

To learn more about rendering Quarto documents and websites with CI, read this article. The article discusses a continuum that extends from running everything locally to running everything remotely on a CI server. The workflow presented in this post sits in the middle:

Graphic of continuous integration continuum with double sided arrow. On the very left is Local Execution & Rendering where the local machine runs code and renders the site and the C server checks the output is copied from version control to the right place. In the middle is Local Execution with CI Rendering where local machine runs code and saves output in the _freeze directory and the CI server with Quarto installed renders the site. The right is CI Execution and Rendering where the CI server executes all code and renders the site; Quarto and all code dependencies must be available on the CI server.

The complete walk-through

If you’re still interested in creating a website with Quarto and publishing with Netlify, follow along to get started!

1 Create a Quarto website

In RStudio, go to File > New Project > New Directory to open the New Project Wizard.

Let’s start with a website. If you’d like to add a blog later on, Samantha Csik wrote a great blog post explaining this process (Csik 2022).

New project wizard with box around Quarto Website.

Are you new to GitHub?

I’m assuming you already use GitHub and connected it to RStudio. If you haven’t, please follow the installation instructions in Happy Git and GitHub for the useR (Bryan and Hester 2023) and then come back.

Choose the name of our directory (which will also be the name of our GitHub repository), check the Create a git repository box, then click Create Project.

Create Quarto Website dialog box with a field for directory name and a checkbox selected to create a git repository.

We should now be in a RStudio project that has index.qmd and _quarto.yml open and some new things in our Files pane:

RStudio with index.qmd and _quarto.yml open and many new folders and files in the files pane.

Our Files pane should have the following:

├── _quarto.yml         # Website configuration file
├── about.qmd           # About page
├── index.qmd           # Landing page
├── my-website.Rproj    # RStudio project config file
└── styles.css          # CSS file for any custom styling

Notice we also have a Git pane with all of these files unstaged and no branches available. This is because we haven’t created a repository on GitHub and connected it with this project yet.

RStudio Git pane with a box around (no branch).

2 Create and connect to GitHub

If you’re following along with Happy Git and GitHub for the useR (Bryan and Hester 2023), we’re using the Existing project, GitHub last workflow.

Thankfully, we can use the usethis package so we don’t have to touch the terminal (yet)! If you haven’t used usethis yet, you’ll need to do the setup described in the package documentation.

Assuming we’ve connected and authenticated our GitHub account in RStudio, we use just two lines of code to create and connect a repository️ to our project 🧙🏼‍♀️.

usethis::use_git()
# ✔ Setting active project to '/Users/jadeyryan/Library/CloudStorage/Dropbox/Mac/Documents/my-website'
# ✔ Adding '.Rhistory', '.Rdata', '.httr-oauth', '.DS_Store', '.quarto' to '.gitignore'
# There are 6 uncommitted files:
# * '_quarto.yml'
# * '.gitignore'
# * 'about.qmd'
# * 'index.qmd'
# * 'my-website.Rproj'
# * 'styles.css'
# Is it ok to commit them?
#
# 1: Negative
# 2: Nope
# 3: Yeah
#
# Selection: 3
# ✔ Adding files
# ✔ Making a commit with message 'Initial commit'
usethis::use_github()
# ℹ Defaulting to 'https' Git protocol
# ✔ Creating GitHub repository 'jadeynryan/my-website'
# ✔ Setting remote 'origin' to 'https://github.com/jadeynryan/my-website.git'
# ✔ Pushing 'main' branch to GitHub and setting 'origin/main' as upstream branch
# ✔ Opening URL 'https://github.com/jadeynryan/my-website'

Our new GitHub repository should open in our browser.

3 Connect and publish to Netlify

In order to use Netlify’s continuous deployment, we need to connect our Git provider to our Netlify account. If you don’t have a Netlify account yet, you can sign up with GitHub.

Netlify signup page with GitHub login.

Once we’re logged into Netlify and connected to our GitHub, we can do the initial publishing with the Quarto CLI. In the terminal, run:

Terminal
quarto publish netlify

If you’re not already logged in to Netlify on your browser, there may be an additional authentication step.

quarto publish netlify command run in the RStudio terminal.

This command rendered our site locally, uploaded all the static files to Netlify, and then deployed and published our new site! The site overview on Netlify should have opened in our browser:

Site overview on Netlify with boxes around the random subdomain name and the status as a manual deploy.

Netlify provided a random site name (stately-chimera-0c91c7) on the netlify.app domain. Also, notice that it says Manual deploys underneath the site link, meaning it was deployed from the quarto publish netlify command in our terminal and not from GitHub.

Click on that link to open our live site!

Screenshot of live website at stately-chimera-0c91c7.netlify.app.

3.1 Site domain name

The domain name is the URL or web address to our site. We have two options to rename our site:

  • Free: change the random name provided but keep the netlify.app domain.
  • Purchase a new domain: I recommend buying it directly on Netlify so they handle all the DNS configurations. Or, buy from a domain provider that doesn’t use the NS1 DNS zone, or you might go through the nightmare of switching DNS zones.5

Free domain name change

Let’s walk through the free option first.

From the site overview Netlify page, click on Site configuration.

Netlify website site overview with box around site configuration.

Scroll down to Site information, and then click on Change site name.

Site information page on Netlify with button to change site name.

Now we can update the site name and click Save:

Netlify change site name dialog box with new name of my-website24.netlify.app.

Note our site name is just the prefix to the full URL containing netlify.app.

Buy a domain name

If you don’t want the netlify.app domain, you can purchase your own. Instead of Site configuration, go to Domain management, and then click Add a domain.

Domain management part of Netlify site with option to add a domain.

Type in whatever custom domain we want. There are a bajillion different extensions – domain.com lists them alphabetically and has a helpful FAQ about domain extensions. my-website24.com is available for $13.99 for the first year.

Add a custom domain to your site page on netlify. It says my-website24.com is available and costs $13.99 for the first year.

3.2 New _publish.yml file

Now that we’re set up with Netlify and GitHub, let’s head back to RStudio. Notice this new file _publish.yml appeared in the project directory when we used the quarto publish netlify command:

_publish.yml
- source: project
  netlify:
    - id: b9f73a69-06e7-4de2-9c7b-4f9855b56ba3
      url: 'https://stately-chimera-0c91c7.netlify.app'

The Netlify site ID and original random URL were automatically filled in.

The next time we manually publish from the terminal, it will ask if we want to publish the update to https://my-website24.netlify.app. If we enter y, it will update the url value in the _publish.yml file.

Terminal
(base) MacBook-Pro-4:my-website jadeyryan$ quarto publish netlify
? Publish update to: › https://stately-chimera-0c91c7.netlify.app (Netlify - jadey.nicole.ryan@gmail.com)
Rendering for publish:

[1/2] index.qmd
[2/2] about.qmd

[✓] Preparing to publish site
[✓] Uploading files (complete)
[✓] Deploying published site
[✓] Published site: https://stately-chimera-0c91c7.netlify.app

(base) MacBook-Pro-4:my-website jadeyryan$ quarto publish netlify
? Publish update to: › https://my-website24.netlify.app (Netlify - jadey.nicole.ryan@gmail.com)
Rendering for publish:

[1/2] index.qmd
[2/2] about.qmd

[✓] Preparing to publish site
[✓] Uploading files (complete)
[✓] Deploying published site
[✓] Published site: https://my-website24.netlify.app
Important

If you continue to the next steps for configuring continuous deployment, this should be your last time manually publishing your site with quarto publish netlify in the terminal.

When adding code content, you should still run quarto render in the terminal to update the _freeze directory. Though, it’s good practice to always render before pushing to GitHub.

4 Configure continuous deployment

Now we need to configure several things so Netlify can automatically deploy and publish our site:

  • Add Quarto Netlify plugin files
  • Freeze code output by setting freeze: auto in _quarto.yml
  • Ignore output directory by adding the _site directory to .gitignore
  • Link Netlify site to GitHub repository6

4.1 Configure Netlify plugin

The Quarto Netlify plugin installs Quarto on the Netlify build server, allowing Netlify to build our Quarto website.

Let’s create the netlify.toml and package.json files in our RStudio project and copy/paste the below content into these files.

netlify.toml
[[plugins]]
package = "@quarto/netlify-plugin-quarto"
package.json
{
  "dependencies": {
    "@quarto/netlify-plugin-quarto": "^0.0.5"
  }
}

4.2 Freeze computations

We need to freeze computations so code only runs locally. When we render a .qmd that executes code on our local machine, the results get saved in a html.json file within the _freeze directory. This means that the CI server has access to the code output and doesn’t need to execute any of the code.

The _freeze directory and all its files must be committed to our repo. Otherwise, the build will fail because Netlify doesn’t have the code output and can’t execute code without R installed. See the detailed error in my comment on a GitHub issue.

To automatically freeze all computations, add these two lines to our _quarto.yml file:

_quarto.yml
execute:
  freeze: auto

Setting freeze: auto tells Quarto to only re-render code when the source changes.

If you need to execute code within a CI service, see the Quarto docs for example GitHub Actions that install Quarto, R, and all dependencies.

4.3 Ignore output directory

Because we want Netlify bots to use continuous deployment to build our site, we need to ignore our output directory. To do this, we add the _site directory that contains all the rendered website content to our .gitignore file. This is recommended in the Quarto docs to avoid super messy diffs and potential merge conflicts.

.gitignore
/_site/
Note

If you’re not following the workflow in this blog post and instead are using the Local Execution & Rendering option of the CI continuum described in the Quarto docs, do not add _site to your .gitignore. You need this directory checked into version control so Netlify can access this content to publish your website.

4.5 Push a change to our repo

Let’s push a change to our repo and make sure it automatically redeploys and republishes our website!

Add some content to about.qmd, run quarto render in the terminal, and then push to main.

GitHub repository with recent commit 0b8b526.

The Deploys page on Netlify tells us that we successfully published from main@0b8b526.

Netlify site Deploys page that shows main@0b8b526 was successfully published.

Auto publishing

By default, auto publishing is turned on in the Netlify deploy settings. This means all successful deployments are automatically published to the public site.

Optionally, you can turn this setting off so that you have to click Publish to send the deployment to production. If you do want to turn it off, go to Deploys > and then click Lock to stop auto publishing.

Netlify site Deploys page with box around button to Lock to stop auto publishing.

The site will still deploy every time you push changes to your repo, but you need to click a button to actually publish this latest deployment. This is a good option if you don’t want to work in new branches or use pull requests/merges, but still want to preview your site before sending it to production.

For my personal website, I don’t have this turned off so that the site will automatically publish anytime I push to GitHub. Otherwise I might forget to click Publish and wonder where my changes are 😅.

Netlify docs provide more detail about auto publishing.

5 Branch deploys and deploy previews

As we work on our website styling, content, and features, we probably want to preview our changes without messing up our live site. This is where the Netlify deploy preview system comes into play!

The table below (adapted from Netlify docs) provides a quick comparison of the differences between branch deploys and deploy previews.

Branch deploys Deploy previews
Default setup Must setup on Netlify website7 No setup needed
URL

<branch-name>–<website>.netlify.app

ex. https://stagingmy-website24.netlify.app/

deploy-preview-<PR#>–<website>.netlify.app

ex. https://deploy-preview-1my-website24.netlify.app/

Access Deploys section on Netlify Deploys section on Netlify or Netlify bot comment on GitHub pull/merge request
Scope Changes from feature branch Changes from pull/merge request

5.1 Branch deploys

Branch deploys are great if you typically use feature branches in your workflow.

By default, only the production branch (typically main) is automatically deployed by Netlify.

To enable branch deploys on other branches, we need to change the branch deploy setting. On the Netlify website > Site Configuration > Build & deploy > Continuous deployment > Branches and deploy contexts > Branch deploys > Configure > select the All radio button > and then click Save.

Netlify site configuration webpage with the branches and deploy contexts settings open. Branch deploys is set to All instead of None.

Or, if we only want to deploy previews for a specific branch, select Let me add individual branches and then enter the name of that branch.

Let’s try it out by creating a new branch called staging and pushing a commit to it.

On the Netlify Deploys page, we see our live site is still published from main, but we now have a Branch deploy from the staging branch that we can click to preview.

Netlify deploys webpage for demo site highlighting the published site is deployed from the main production branch. Lower on the screen is the branch deploy which shows it was deployed from the staging branch.

Once we merge our staging branch into main, those changes will be published to our site in production.

5.2 Deploy previews

Deploy previews are enabled by default once our Netlify site is linked with our GitHub repository. Every time we make a pull request or merge, Netlify will deploy our site and then provide the links to the deploy information as a comment in the pull request/merge conversation on GitHub.

From our GitHub repository, create a pull request to merge our staging branch into main.

This triggers Netlify to deploy the site and then comment all the information for the deploy preview including a link to the commit, the deploy log, preview link, and a QR code to preview on a mobile device.

GitHub merge request. Netlify bot commented a table with links to the latest commit, latest deploy log, deploy preview, and preview on mobile QR code.

We can also access our deploy preview from the Netlify Deploys page. Similar to the branch deploy, our live site is still published from main, but we now have Deploy Preview #2 from staging. The #2 just means this was the second pull/merge request in our repository.

Netlify deploys webpage for demo site highlighting the published site is deployed from the main production branch. Lower on the screen is the deploy preview which shows it was deployed from Pull Request #2.

Once we complete our pull request and merge to main, those changes will be published to our site in production.

6 Lighthouse plugin

Another benefit of Netlify are the integrations with different web tools. The only one I’m using so far is the Google Lighthouse tool, which helps me abide by my accessibility commitment.

Once installed, the Lighthouse plugin audits our site for performance, accessibility, best practices, and SEO at build time. The Lighthouse report gives us scores for each of these four categories.

To enable the plugin, on Netlify > go to Integrations > search for lighthouse > then click Enable.

Netlify integrations page searching for lighthouse with box highlighting the Enable button for the Lighthouse plugin.

Netlify will then ask if we’re sure we want to install Lighthouse on our website.

If we click Install, the Lighthouse audit will run the next time we deploy our site.

Lighthouse report on Netlify

Regardless of whether we push directly to main or use the deployment preview system, we can always see the Lighthouse scores on the Netlify deploys page.

Netlify deploys page with box around Lighthouse scores for performance (score of 96), accessibility (score of 86), best practices (score of 100), and SEO (score of 82).

Lighthouse report on GitHub

If we have a pull or merge request open, the Netlify bot will include the Lighthouse scores in its deploy preview comment.

GitHub pull request conversation with netlify bot comment that was edited with the latest commit, deploy log, preview URL, and Lighthouse audit.

Note

You can also manually run a Lighthouse report in Chrome DevTools. But that takes away from the magic of the automated audit everytime you deploy your site with Netlify 😉.

Workflow

My general workflow for editing my website is:

  1. Add, edit, or remove content.

  2. Run quarto preview in the terminal and work iteratively.

  3. Use Command+Shift+C on Mac or Control+Shift+C on Windows to open Chrome DevTools and then Command+Shift+M on Mac or Control+Shift+M on Windows to toggle device mode for testing the webpage responsiveness on mobile.

  4. When happy with the changes, run quarto render in the terminal.

  5. Push changes to GitHub (usually in a new branch).

  6. Preview changes on different devices because I don’t fully trust Chrome DevTools device mode!

  7. Edit based on Lighthouse audit scores.

  8. Rinse and repeat!

Wrap up

I hope you found this post helpful for getting your Quarto website configured with Netlify, GitHub, and continuous deployment!

Since this is my first blog post, I’d love feedback on the style, flow, helpfulness, content, etc. Now that I’ve experienced the massive amount of time and head space writing a blog post can take, I have an even deeper appreciation for all the bloggers out there! Thank you!

References

Bryan, Jennifer, and Jim Hester. 2023. Lets Git Started | Happy Git and GitHub for the useR. https://happygitwithr.com/.
Csik, Samantha. 2022. “Adding a Blog to Your Existing Quarto Website.” October 24, 2022. https://samanthacsik.github.io/posts/2022-10-24-quarto-blogs/.

Footnotes

  1. See my GitHub stars list for my favorite blogs or Quarto website resources.↩︎

  2. As long we Configure Netlify plugin.↩︎

  3. Unless we have a GitHub Action install R and package dependencies.↩︎

  4. Check out my GitHub issue comment to see what happens if we don’t have freeze set to auto or true AND commit the freeze outputs.↩︎

  5. I originally bought a domain from Square Space and could not set my Netlify site to that domain due to DNS issues that I don’t fully understand. When trying to add a domain, Netlify gave this error message: A DNS zone for this domain already exists on NS1, the DNS provider backing Netlify DNS. Please contact NS1 with the domain name for support. Here’s a support forum thread on Netlify with the instructions for pointing a custom domain to a Netlify site. I ended up buying another domain directly from Netlify… DNS stuff is too confusing! 😵‍💫↩︎

  6. We’ve already connected our GitHub account to our Netlify in Create and connect to GitHub and Connect and publish to Netlify, but we still need to pick which repository our Netlify site links to.↩︎

  7. Set up branch deploys by going to Netlify.com > [Your website] > Site configuration > Build & deploy > Continuous Deployment > Branches and deploy contexts↩︎

Citation

BibTeX citation:
@online{ryan2023,
  author = {Ryan, Jadey},
  title = {Intermediate Guide to Publish a {Quarto} Website with
    {GitHub} \& {Netlify}},
  date = {2023-11-19},
  url = {https://jadeyryan.com/blog/2023-11-19_publish-quarto-website},
  langid = {en}
}
For attribution, please cite this work as:
Ryan, Jadey. 2023. “Intermediate Guide to Publish a Quarto Website with GitHub & Netlify.” November 19, 2023. https://jadeyryan.com/blog/2023-11-19_publish-quarto-website.
Subscribe to get notified about new content.
Thumbnail for the data whiskeRs blog. Dark teal color with white text reading data whiskeRs: R code & data science content with a sprinkle of cute cats.