Table of Contents

Run it, then build it

You have run npm start twice already, so the dev server is not news. A build is a different site, though, and the gap between the two is where the surprises live.


The dev server

npm start

It serves on http://localhost:8080/ and rebuilds whenever you save. It also writes to dist/ as it goes, so you can open the generated files while the server is running and see what your Markdown became.

Eleventy never empties dist/ for you. That is why both scripts run rimraf first: a page you deleted last week would otherwise still be sitting there, still being served, looking entirely convincing.


Build it for production

A build wants a real origin, so the absolute URLs come out pointing somewhere that exists. Set it for the one command:

BASELINE_URL=https://www.example.com/ npm run build

Three things change compared to npm start. Your CSS is minified, because the build script sets ELEVENTY_ENV=production and Baseline's PostCSS config turns on cssnano when it sees that. The navigator page, a development-only introspection page you have not met yet, is left out for the same reason. And any page marked draft: true in its front matter is dropped, this time because Eleventy itself knows it is building rather than serving. Two switches, not one.

Then the BASELINE_URL in front of the command. Everything absolute that Baseline emits, the canonical link on every page and every entry in the sitemap, is anchored to that value. A build without a real origin produces a site that quietly tells search engines it lives on your laptop. The start script hardcodes localhost because that is where dev runs; a build has no such fixed answer, so it takes one from you. On a real deployment your host sets BASELINE_URL and you never think about it again.

The NAME=value prefix works in bash and zsh. Windows cmd and PowerShell do not take it, which is what cross-env is for. It is already installed, and it belongs inside the build script in package.json rather than typed at the prompt.


Read what came out

Open dist/. Five things are worth a look before you close the folder again.

dist/index.html, and specifically its <head>. You never wrote one. Everything in there came from your front matter and your settings file, sorted and deduplicated on the way out.

dist/sitemap.xml, which nobody asked for. The sitemap module is on by default and lists all three of your URLs, the post included, and they start with the origin you passed rather than localhost. If they say localhost, BASELINE_URL did not reach the build.

dist/posts/hello-world/index.html, next to dist/about/index.html. Two folders, two kinds of thing, and the addresses came from two different rules in two different directory data files. Neither page knows which rule made it.

dist/posts/not-finished/, which is not there. The draft has been showing up in the browser since you wrote it two pages ago, and it never reached the build. The sitemap above lists three URLs rather than four for the same reason.

dist/assets/css/index.css, now on a single line. That is the minification, and it is the visible proof that ELEVENTY_ENV did its job.

Everything past this point is deployment, which has enough of its own things to check that it gets a guide of its own. The next page points you at it.