Hosting and infrastructure

Publishing a site with GitHub and Netlify: atomic deploys, previews and the workflow I use every day

From FTP to GitHub and Netlify: atomic, immutable deploys, a preview for every change, instant rollbacks, per-context variables, redirects in code, serverless functions. And when it is not the right fit.

Fabio Folgori6 min read

A rocket climbing into the sky at dusk, leaving a trail of light
Photo by SpaceX on Unsplash

For years, publishing a site meant dragging files onto a server via FTP and hoping not to overwrite the wrong one. Today all my new projects go through GitHub and Netlify, this site included. It is not a fashion choice: it is the workflow that lets me work more safely, verifiably and quickly, and show every change to the client or agency before it goes live.

The workflow, in short

The code (and often the content, in Markdown) lives in a GitHub repository. Netlify is connected to it: on every push it runs the build in a clean environment and publishes the result to its CDN. Every pull request generates a Deploy Preview, a separate test address with the complete, working site. When the change is approved and merged into the main branch, the production deploy starts.

What changes technically

Atomic, immutable deploys

With FTP the site goes through an intermediate state while the files upload: half old, half new. On Netlify the new version is built in full and activated in a single step: visitors see either the previous version or the new one, never a hybrid. Retained deploys keep a reference to the published version. Historical availability depends on the plan's retention rules.

Instant rollbacks

Because deploys are immutable, going back requires no rebuild: you reactivate the previous one. In parallel, every change has a commit on GitHub that can be reverted and republished.

A preview for every change

This is the most visible benefit for whoever commissions the work. The Deploy Preview lets you check the proposed version at a separate address, on phone and desktop. I use test or minimised data and separate access; when needed I protect the preview from public access. The agency or client approves the product, not screenshots.

Reproducible builds

The build runs in a clean environment with Node and dependency versions pinned by the lock file. This reduces the differences between environments, but does not remove them: variables, data, domains, external services and permissions must be checked in the production context too.

Configuration in code

Redirects, security and cache headers and per-deploy-context rules live in project files, versioned and reviewed like everything else. No dashboard that someone edits by hand without leaving a trace. Environment variables are separated by context: production, previews, branches. The separation must be configured explicitly: variables can have the same value in all contexts by default. Reserved keys stay on the server side, and previews get test credentials with only the permissions they need.

Serverless functions and forms

Dynamic parts are written as serverless functions that run only when needed: this site's AI chat, for example, is a server route that reads the knowledge base and calls the model API, with the key never reaching the browser. Contact forms go through Netlify Forms, with no server to maintain. HTTPS is enabled and renewed automatically.

A smaller attack surface

A site generated in advance has no database needed to run the application and no public login panel. What remains to protect are the GitHub, Netlify and domain registrar accounts, with two-factor authentication. The comparison with WordPress is in Hacked WordPress site.

My workflow

It is the same one I use for this site:

  1. one branch per topic, with a name that says what it contains;
  2. small, described commits;
  3. a pull request on GitHub, with the Deploy Preview generated by Netlify;
  4. review on the preview, together with whoever approves;
  5. merge into the main branch, which is never touched directly, and an automatic production deploy.

That way every change has a history, a preview and a way back.

Domain, DNS and email

Two recommendations I often see neglected. The domain must be registered to the site owner, with auto-renewal and registrar access under their control. Email stays on a dedicated service, separate from the site hosting, with SPF, DKIM and DMARC configured: moving the site to Netlify must not touch email, and DNS records have to be changed with that in mind.

When it is not the right fit

  • Large non-technical editorial teams without a connected headless CMS: Git is not a writing tool for everyone.
  • Applications with particular execution requirements or persistent connections: I assess the limits of functions and the managed services available; some backend components may require a different infrastructure.
  • Complex WooCommerce stores that work well: moving them costs more than it rarely returns.
  • Sites that already work well on traditional hosting, fast, secure and up to date.

The limits of rollback

Republishing a previous deploy restores the artefacts available for that version; it does not automatically restore the database, external services or data changed by users. An incompatible migration can therefore make the old code unusable even after a successful rollback.

For changes to the data model I use compatible steps: first I add the new field or schema while keeping the previous one, then I migrate the data and update the readers, and finally I remove what is no longer needed after the verification period. Before a release I check which deploys are still available and how to pause automatic publications while I handle the restore.

The preview uses values and test services explicitly assigned to its context; a separate address alone does not isolate data and secrets.

References: managing and rolling back deploys, environment variables.

My take

Since working this way I would not go back. The difference is not only technical: it changes the relationship with whoever commissions the work. Instead of "I've uploaded it, take a look", I send a preview link and the real site to look at. Instead of "let's hope the update doesn't break anything", there is a deploy that can be undone with one click. It is also why, when a project does not need a dynamic admin panel, I suggest moving from WordPress to Nuxt.js and publishing this way.

There is also a transparency aspect clients appreciate: the repository history is a readable record of everything that was done, with dates and descriptions. There is no need to trust a report: the work is there, verifiable, and it remains the client's property even if one day they choose another developer.

Why work with me

I have been publishing sites for years: since 1999 I have delivered more than 300 projects and I work with more than 30 agencies, from Rome and remotely. This site is built with Nuxt.js and published with GitHub and Netlify: I set up the same workflow, with previews, redirects and per-context variables, and leave it documented for you or your agency.

If you want to know whether this way of publishing suits your site, get in touch: in a call of about 20 minutes we look at how you publish today. The service is in Hosting and infrastructure.

Frequently asked questions

For most presentation sites, no: entry plans cover normal traffic. Costs and limits change over time, so they should be checked for the specific case, especially for frequent builds, serverless functions and bandwidth.

No, if the site is connected to a headless CMS with a writing interface: the editor publishes from the panel and the build starts automatically. With Markdown content, Git becomes the editing tool.

You can republish a previous deploy that is still available, without rebuilding it. Availability depends on the service

Not as the main workflow: WordPress needs PHP and a database running at all times. You can use WordPress only as a headless CMS and publish the generated front end on Netlify.

  • #netlify
  • #github
  • #deploy
  • #hosting
  • #nuxt

More articles

// Contact

A project, a problem or just a question?

Agency, business or professional: choose how you'd rather talk to me. I reply as soon as I can, no strings attached.