Preview a Hugo Site Locally with hugo server
Fire up hugo server on the wrong interface and you have quietly published your draft posts to anyone on the same network. This guide starts it safely on loopback, then walks through the switches that decide what gets built and where. Examples target the installed Hugo 0.123.7 package.
The route
Jump straight to the step you need, or tick off Done means at the end.
Before you start
- Have a Hugo site directory containing
hugo.toml,hugo.yamlorhugo.json. - Run the commands as your normal user: the development server never needs
sudo. - Use a terminal you can leave running. Press
Ctrl+Cto stop the server. - Allow about 10 minutes if the site already exists, or 20 if you are building a small test site first.
Confirm which executable runs and record its version:
$ command -v hugo
/usr/bin/hugo
$ hugo version
hugo v0.123.7+extended linux/amd64
The build metadata after the version string can differ between package builds. The part that matters here is the release: 0.123.7.
1. Start on the loopback address
Replace /path/to/site with the directory holding your Hugo configuration. An explicit port makes the address easy to recognise instead of relying on the default:
$ hugo server --source /path/to/site --bind 127.0.0.1 --port 1313
Hugo watches the site by default, rebuilds on changes, and normally enables live reload in open browser pages. A successful start looks like this:
Serving pages from disk
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
Checkpoint
Leave this process running, visit http://127.0.0.1:1313/ in a browser, and from another terminal check the HTTP response without touching the site:
$ curl -I http://127.0.0.1:1313/
A response beginning HTTP/1.1 200 or HTTP/2 200 confirms a page was served. A 404 can still mean the server is healthy: an empty site, or one without a matching home template, may simply have no page at that path.
2. Decide what content belongs in the preview
Hugo excludes content marked draft, expired, or scheduled for the future by default. That is a useful publication boundary, and it is also the thing that surprises you mid-write. Add only the switch that matches what you are deliberately previewing:
$ hugo server --source /path/to/site --buildDrafts
$ hugo server --source /path/to/site --buildFuture --buildExpired
These flags change the build view; they do not edit front matter or publish anything. If a page still will not show, check its front matter, section, layout and URL before reaching for every build flag.
Checkpoint
Stop the first server with Ctrl+C, then restart with the smallest set of switches you actually need. That stops you accidentally previewing unpublished material during a screen share or a local network test.
3. Fix a reload loop that gets in your way
- Disable live reload when another tool, proxy or browser session produces confusing refreshes:
$ hugo server --source /path/to/site --disableLiveReload - Force a full rebuild for a template or configuration change that fast render does not explain:
$ hugo server --source /path/to/site --disableFastRender
A stale browser page is not proof that Hugo failed. Check the terminal for build warnings first, refresh manually, and only keep the full rebuild switch on while you are diagnosing: it makes repeated edits slower.
4. Choose where Hugo renders files
By default Hugo serves generated pages from disk. --renderToMemory keeps rendered output in memory, which can be faster at the cost of more RAM, useful for a quick preview where nothing else needs to inspect the generated files:
$ hugo server --source /path/to/site --renderToMemory
If static files need to stay on disk while dynamic files render in memory:
$ hugo server --source /path/to/site --renderStaticToDisk
These are server-mode choices, not a substitute for a production build. For a deployable output directory, stop the server and use your site's normal hugo build workflow.
5. Expose the server only when you mean to
Warning
The default bind address, 127.0.0.1, means other machines cannot connect. Binding to all interfaces can expose drafts, source-derived details and unfinished pages to every reachable device on the network, so do not change it casually.
If you have a controlled private network and genuinely need another device to test the site, bind explicitly and use a non-conflicting port:
$ hugo server --source /path/to/site --bind 192.0.2.10 --port 1313
Replace 192.0.2.10 with the host's actual private address; do not copy that documentation address literally. Check the listening socket before sharing the URL:
$ ss -ltn | grep ':1313'
Recovery
Press Ctrl+C when finished. If you changed the bind address, stopping the process is the undo action: nothing persistent gets changed by the command above.
Common failures
- Address already in use. Choose another port, such as
--port 1314, or stop the other development server once you have confirmed it is yours. Do not kill an unknown process. - Changes are not detected. Use
--poll 700msfor a poll-based watcher, especially on a filesystem that does not reliably report events. - The browser shows a build error. Read the terminal output first.
--disableBrowserErrorhides the browser error page; it does not fix the build. - The site is slow or memory is short. Prefer the default disk rendering and close extra servers. Memory rendering trades disk writes for RAM.
- A page is unexpectedly absent. Check draft, future and expiry state before adding
--buildDrafts,--buildFutureor--buildExpired.
Done means
- hugo version reports the Hugo release you intended to use.
- The server prints an available URL and serves the expected page.
- The bind address is
127.0.0.1unless you made and checked a deliberate exposure decision. - Draft, future and expired content only appears when you explicitly asked for it.
- You can stop the server with
Ctrl+Cand know which temporary option to drop on restart.