To deploy a static site on Netlify you either drag a folder of built files onto the deploy page or connect a Git repository and give Netlify a build command and a publish directory, and the second route is the one that keeps working as the site grows.
The two routes look equivalent on day one and diverge fast. Knowing why saves a migration later.
Table of contents
- Two ways to publish
- Deploy from a Git repository
- Redirects, rewrites and single-page apps
- Domains, HTTPS and environment variables
- Troubleshooting failed or empty deploys
- Static hosting, whatever platform you use
- Previews, rollbacks and keeping deploys boring
- How this fits the rest of the stack
- FAQ
Two ways to publish
A static site is a folder of files: HTML, CSS, JavaScript, images. Deploying it means putting that folder where a web server will serve it. Netlify offers two main ways.
Manual deploy by drag and drop. You build the site on your own machine and drop the output folder onto a page in the dashboard. It uploads and publishes within seconds. No repository and no pipeline are involved, which makes it ideal for a quick demo, a one-off page or a client handover.
Git-connected deploy. You connect a repository from a hosted Git service. Every push triggers a build in Netlify’s environment, and if it succeeds, the result is published. Pull requests can get preview URLs, and each deploy is kept so you can roll back.
The support forum is full of questions from people who started with drag and drop and later wanted automation, or who connected a repository but forgot which folder to publish. A manual deploy has a hidden cost. Nothing records what was published or how it was built, so a second person cannot reproduce it, and an old deploy cannot be rebuilt.
If the site will change more than a couple of times, connect a repository from the start. The effort is a few minutes and the benefit is repeatability. This post is a neutral how-to for that platform, and the same steps apply in spirit to any static host.
Deploy from a Git repository
Start with a repository containing your site source. In the dashboard, add a new site from Git, choose the repository and set three things.
- Branch to deploy. Usually main.
- Build command. The command that turns source into static files, for example
npm run build. For plain HTML with no build step, leave it empty. - Publish directory. The folder holding the finished files, for example
dist,buildorpublic. For plain HTML at the repository root, use the root.
The publish directory is the most common mistake. If you set it wrong, the deploy succeeds and the site shows a 404, because the platform published a folder with no index file in it. Check the build log for the folder your tool actually writes to, and match it exactly.
Click deploy. The build log streams as it runs, and on success you get a live address on the platform’s domain. From then on, each push to the chosen branch redeploys.
You can keep these settings in a configuration file in the repository instead of the dashboard, which makes them reviewable and portable.
[build]
command = "npm run build"
publish = "dist"
Settings in the file travel with the code, so a teammate cloning the repository sees how it deploys without needing dashboard access.
Redirects, rewrites and single-page apps
Static hosting needs rules for URLs that are not plain files. Netlify reads them from a _redirects file in the publish directory or from the configuration file.
/old-page /new-page 301
/blog/* /articles/:splat 301
/* /index.html 200
The first line is a permanent redirect for one page. The second moves a whole section and keeps the rest of the path. The third is the single-page-app fallback: any path that does not match a file serves index.html with a 200 status, so client-side routers such as React Router work on refresh. Order matters, and the first matching rule wins, so put the specific rules above the catch-all.
If your deep links return a 404 after deploy, a missing fallback rule is the cause nine times out of ten. A subtler issue is trailing slashes: /about and /about/ can be treated differently depending on settings, and mismatches show up as duplicate URLs in search. Pick one form and redirect the other.
For custom headers, such as security headers or long cache lifetimes for fingerprinted assets, a _headers file works the same way.
/assets/*
Cache-Control: public, max-age=31536000, immutable
Keep the rules small and tested. A broad rewrite can swallow paths you meant to serve as real files.
Domains, HTTPS and environment variables
Every site gets a default address. To use your own domain, add it in the site settings and point DNS at the platform, either with a CNAME for a subdomain or by delegating the domain’s nameservers. A certificate is then issued and renewed automatically, so HTTPS needs no manual steps once DNS resolves. Wait for propagation before you assume something is broken.
Build-time environment variables are set in the dashboard and are available to the build command. For a static site, remember that anything inlined into the final JavaScript is public. Never put a private API key in a variable that your front end bundles. Keep secrets on a server-side function or a separate API.
If the site needs dynamic features such as forms or small APIs, the platform offers form handling and serverless functions. They are convenient and they tie some behaviour to the platform. Isolate that code behind a thin layer so you could move it later without rewriting the site. The existing posts on Netlify forms and redirects on Netlify go deeper on both.
Finally, set the Node version if your build depends on one. A build that works on your laptop and fails in the platform’s environment is frequently a version mismatch.
Troubleshooting failed or empty deploys
Most problems fall into a few categories.
- Build fails with a missing command. The build script is not defined or the dependency install step failed. Run the same commands locally from a clean checkout.
- Deploy succeeds and the site is a 404. The publish directory is wrong, or the build wrote to a different folder.
- Works locally, fails on the platform. A Node version mismatch, a case-sensitive file path on Linux, or a missing environment variable.
- Old content keeps appearing. Browser or CDN caching. Hard refresh, check cache headers and confirm the latest deploy is the published one.
- Deep links 404 after refresh. Add the single-page-app fallback rule.
- Assets load from the wrong path. A base path or homepage setting in your build tool does not match the deployed location.
Read the build log from the top. The first error is usually the real one, and the later failures are consequences. Most platforms let you retry a deploy with a cleared cache, which resolves stale dependency problems.
Keep a habit: after each deploy, open the live site and click through two or three pages, including a hard refresh on one deep link.
Static hosting, whatever platform you use
Everything above has a counterpart on any static host. A build command, a publish directory, redirects and rewrites, headers, a custom domain with an automatic certificate, rollback to a previous deploy. If you understand those six, you can move a static site between platforms in an afternoon.
RunxBuild static sites follow the same model. They build from a GitHub repository, support custom domains, headers, redirects, rewrites and SPA fallback, and include 120GB of bandwidth, then $0.10 per GB. If a site outgrows static, an API can run as a web service and a database as managed MySQL or Postgres on the same platform. The static builds docs describe the build and output settings, and the redirects docs cover the rules.
Keep your site portable by avoiding platform-specific features where a standard alternative exists, so the choice of host stays a decision you can revisit.
Previews, rollbacks and keeping deploys boring
Two features make Git-driven static hosting pleasant. Preview deploys give every pull request its own address, so reviewers see the actual rendered change instead of reading a diff. And every production deploy is kept, so a bad release is undone by publishing the previous one, which takes seconds and needs no rebuild.
Use both. Require a preview check before merging, and practise a rollback once so the steps are familiar. A deployment process works best when nothing about it is exciting.
How this fits the rest of the stack
A static site is the cheapest thing to host, and bandwidth is the line item that grows with success. Estimate yours in the RunxBuild hosting calculator. When the build output is ready, the RunxBuild dashboard is where you connect a repository and publish.
Useful related references:
- Can You Host a Webflow Site on Netlify? What Actually Happens
- Serving a Site in China: What the Great Firewall Actually Blocks
- Netlify’s CDN: How the Edge Network Actually Serves a Site, What It Caches, and What It Costs When Traffic Arrives
- Static sites on RunxBuild
FAQ
How do I deploy a static site to Netlify?
Drag the built folder onto the deploy page for a quick publish, or connect a Git repository and set the build command and publish directory so every push redeploys automatically.
What should the publish directory be?
The folder your build writes the finished files into, such as dist or build, or the repository root for plain HTML. A wrong value gives a successful deploy and a 404 site.
Why do my routes 404 after refreshing?
Single-page apps need a fallback rule that serves index.html with a 200 status for unknown paths. Add it to your redirects file or configuration.
Is drag and drop deployment fine for production?
For a rarely changed page, yes. For anything that changes often, connect a repository, because manual uploads leave no record of how a deploy was built and cannot be reproduced.
How do I use my own domain?
Add it in the site’s domain settings and point DNS at the platform with a CNAME or by delegating nameservers. A certificate is issued automatically once DNS resolves.