You remember the dream, right? The one where you’d start a simple blog, a personal portfolio, or just a little corner of the internet to share your thoughts. You’d just write your content, hit a button, and—poof—it’s live. Simple, clean, and fast.
And then, reality hit.
You installed WordPress or some other big-box Content Management System (CMS). Suddenly, you were wrestling with databases, PHP versions, security plugins, and a constant barrage of updates. That theme you bought never quite did what you wanted. Your simple dream was now a part-time, unpaid job as a system administrator.
Believe me, I’ve been there. I’ve burned entire weekends trying to fix a mysteriously broken plugin or optimize a sluggish database query for a site that had maybe a dozen pages. It always felt like using a sledgehammer to hang a picture frame.
But what if I told you there’s a way to get back to that original dream? A way to build incredibly fast, secure, and genuinely delightful-to-manage websites using skills you probably already have—like writing in simple text files.
Welcome, my friend, to the world of Static Site Generators (SSGs). This isn't just another tool; it's a completely different philosophy for building on the web. And in this tutorial, we're going to walk through it together, from a completely blank folder to a live website.
So, What Exactly Is a Static Site Generator?
Let's try to break this down with an analogy. Stick with me here—imagine you run a bakery.
The Dynamic Website (like WordPress) is like a fancy, on-demand bakery. A customer walks in and orders a custom cake. You have to scramble—you grab the flour, eggs, and sugar, mix the batter, bake it, let it cool, frost it, and finally, present it to the customer. It’s powerful and highly customizable, but it takes time and energy for every single order. If ten people order at once, you’re going to be very, very busy.
The Static Website is like a bakery that pre-bakes its most popular cakes first thing in the morning. When a customer walks in, the cake is already sitting there, perfectly finished and ready to go. You just hand it over. It’s instantaneous.
A Static Site Generator is the master baker who comes in before the shop opens and bakes all those cakes.
So, in web terms, an SSG takes your content (usually written in a simple format like Markdown), mashes it together with some templates (to define the header, footer, and overall look), and spits out a complete, ready-to-serve website made of plain old HTML, CSS, and JavaScript files. It does all the "baking" upfront, just once, during a "build process."
The result? A collection of simple, static files that can be hosted almost anywhere, often for pennies (or even free!), and served to users at lightning speed. There's no database to query, no server-side code to execute for each visitor. It's just… files. Simple, beautiful files.
The "Why": Why This Changes Everything
Okay, so it’s a different approach. But why should you actually care? Let me tell you, once you experience the static-first workflow, it's incredibly hard to go back. The benefits are just too good.
1. Blazing Speed
This is the big one, the headline feature. Since your website is just a collection of pre-built HTML files, a web server’s only job is to find the file a user requested and send it. That's it. There’s no complex dance between a server, a database, and a templating engine happening every single time someone loads a page.
The difference in performance isn't just measurable—it's palpable. We're talking load times well under a second, which is huge for both your visitors' happiness and Google's SEO rankings. Let’s be real, nobody waits for a slow website anymore.
2. Fort Knox-Level Security
Think for a second about the most common ways websites get hacked. It's almost always through vulnerabilities in the server-side language (like PHP), the database, or some poorly coded plugin.
With a static site, you essentially remove that entire attack surface. There's no live database to breach. There are no server vulnerabilities to exploit because there's no server-side processing happening for visitors. The security is almost... well, boring. And in the world of web security, believe me, boring is fantastic.
3. A Dreamy Developer Experience
This is the part that I personally love the most. Working with an SSG just feels like coming home.
- You write in Markdown. It's clean, simple, and lets you focus purely on your words and ideas.
- Everything is in version control. Your content, your templates, your configuration—it's all just text files. You can use Git to track every single change, roll back mistakes, and collaborate with others. Just try doing that with a WordPress database.
- The tooling is modern. You're in your favorite code editor, using the command line, and leveraging the massive JavaScript ecosystem. It just feels right for a developer in this day and age.
4. Cheaper and Simpler Hosting
You can host a static site pretty much anywhere. In fact, many services like Netlify, Vercel, and GitHub Pages will host your static site for free. Since there are no special server requirements—no PHP, no database—hosting becomes a completely solved problem. You just upload the files, and you're done.
Choosing Our Weapon: Enter Eleventy (11ty)
Okay, so if you go and Google "static site generator" right now, you're going to see a dizzying array of options: Hugo, Jekyll, Next.js, Gatsby, Astro... the list just goes on and on. It can feel like a paralysis of choice.
For this tutorial, we're going to use a wonderful little tool called Eleventy (or 11ty).
So, why Eleventy? Honestly, it's because it’s beautifully simple and, maybe more importantly, un-opinionated. It doesn't force you into a specific JavaScript framework like React or Vue. It just takes your files, understands how they fit together, and builds your site. It’s flexible, incredibly fast, and works with templating languages you might already know. The official docs call it "a simpler static site generator," and I couldn't agree more.
It's the perfect tool for us to learn the core concepts of SSGs without getting bogged down in a bunch of framework-specific complexity.
Let's Build Something: Your First Static Site with Eleventy
Alright, enough talk. It's time to get our hands dirty. We're going to build a very simple blog from scratch.
Prerequisites
You'll just need a couple of things installed on your machine:
- Node.js and npm: Eleventy is a Node.js package, so this is essential.
- A code editor: I'll be using VS Code, but please, use whatever you're comfortable with.
- A terminal or command line.
Got those? Awesome. Let's do this.
Step 1: Setting Up Your Project
First things first, let's create a new folder for our project and hop inside.
mkdir my-11ty-blog
cd my-11ty-blog
Now, we need to initialize a Node.js project. This command creates a package.json file, which is kind of like the birth certificate for our project. It's where we'll track our dependencies and scripts.
npm init -y
The -y flag just says "yes" to all the default prompts. Easy peasy.
Next, let's install Eleventy as a "development dependency." This just means it's a tool we need for building the site, not for running it in production (because, well, there's nothing to "run"!).
npm install --save-dev @11ty/eleventy
You'll see a node_modules folder and a package-lock.json file appear. Don't worry about them, you can safely ignore them—that's just npm doing its thing.
Step 2: Your First Piece of Content
Okay, this is where the magic begins. Create a new file right in the root of your project called index.md. The .md extension, of course, stands for Markdown.
Inside index.md, go ahead and put the following content:
---
title: "My Awesome Home Page"
---
# Hello, World!
This is my very first page built with a static site generator.
Isn't this cool? I'm just writing in a simple text file.
That little bit at the top between the --- is called front matter. It's a small block of YAML that holds metadata about the page—in this case, a title. Eleventy will read this data and make it available for us to use in our templates.
Now, let's see what Eleventy does with this. In your terminal, run this command:
npx @11ty/eleventy --serve
This command tells Eleventy to build our site and then start up a little local development server so we can see it. You should see some output that looks something like this:
[11ty] Writing _site/index.html from ./index.md.
[11ty] Watching…
[11ty] Server at http://localhost:8080/
Go ahead and open your web browser and navigate to http://localhost:8080.
Boom! You should see your content rendered as a basic HTML page. Pretty cool, right? Eleventy took our Markdown file, converted the Markdown syntax (#) into a proper HTML tag (<h1>), and created a file at _site/index.html. That _site folder is the default output directory—it's our pre-baked website!
Step 3: Creating a Reusable Layout
Okay, that's neat, but let's be honest, it's just a plain HTML fragment. A real website needs a header, a footer, and a proper <html> and <body> structure. This is where layouts come in.
Let's create a folder called _includes. This is a special folder name that Eleventy knows to look in for reusable bits and pieces, like layouts.
mkdir _includes
Inside that _includes folder, create a new file named base.njk. We're using the .njk extension because we'll be writing in Nunjucks, a simple and powerful templating language that Eleventy supports right out of the box.
Now, put this standard HTML structure inside _includes/base.njk:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<header>
<h1>My Amazing Blog</h1>
<nav>
<a href="/">Home</a>
<a href="/blog/">Blog</a>
</nav>
</header>
<main>
{{ content | safe }}
</main>
<footer>
<p>© 2025 Me, Myself, and I</p>
</footer>
</body>
</html>
Let's break down those weird {{ }} things you're seeing:
{{ title }}: This is a variable. Eleventy will look for atitlevalue in the front matter of whatever page is using this layout and plug it in right here.{{ content | safe }}: This is the most important part.contentis a special, magical variable that holds all the rendered HTML from our Markdown file. The| safepart is a Nunjucks "filter" that tells it, "Hey, this content is already HTML, don't try to be clever and escape any of the characters."
So, how do we tell our index.md file to actually use this layout? It's as simple as adding it to the front matter!
Update your index.md file so it looks like this:
---
title: "My Awesome Home Page"
layout: "base.njk"
---
# Hello, World!
This is my very first page built with a static site generator.
Isn't this cool? I'm just writing in a simple text file.
Save the file. If you look at your terminal, you'll see that because Eleventy is still running with the --serve command, it automatically detected the change and rebuilt the site. Now, go back to your browser and refresh the page.
Voilà! Your content is now wrapped snugly inside the full HTML structure from your layout. You've just created a reusable template. This is a fundamental concept in web development, and with an SSG, it's just incredibly straightforward.
Step 4: Building a Blog with Collections
A single page is nice, but we came here to build a blog. So, let's create some posts.
Create a new folder called posts. This is where we'll put all our blog articles.
mkdir posts
Inside the posts folder, let's create two new Markdown files.
posts/my-first-post.md:
---
title: "My First Ever Blog Post"
date: 2025-11-01
layout: "base.njk"
---
This is the body of my very first post. It's so exciting! I'm using Markdown to write it, which makes things like **bold text** and *italic text* super easy.
Here's a list:
* Item one
* Item two
posts/my-second-post.md:
---
title: "A Follow-Up Post"
date: 2025-11-03
layout: "base.njk"
---
I'm getting the hang of this. Writing content feels so... focused. I don't have to click around a clunky web interface.
I can just write.
If you save these, Eleventy will dutifully build them into individual pages. You can even navigate to them directly at http://localhost:8080/posts/my-first-post/ and http://localhost:8080/posts/my-second-post/.
But here’s the really cool part. Eleventy automatically creates something called a collection for any files that live inside a folder. So, just by putting those files in the posts directory, we now have a collections.posts object available to us everywhere in our site. This object is an array containing all the data and content from our post files.
Now, I have to admit, this surprised me the first time I saw it. It's almost too easy. It feels like cheating.
Step 5: Listing Your Blog Posts
Okay, we have posts, but we need a page that lists all of them. Let's create a blog index page.
Create a new file called blog.md in your root directory (right next to index.md).
---
title: "The Blog Archive"
layout: "base.njk"
---
# All My Posts
Here you can find a list of all the articles I've written.
This is a good start, but now we need to actually loop through our posts and display them. And the cool thing is, we can do that right here in our Markdown file using Nunjucks!
Update blog.md to include a loop like this:
---
title: "The Blog Archive"
layout: "base.njk"
---
# All My Posts
Here you can find a list of all the articles I've written.
<ul>
{%- for post in collections.posts -%}
<li>
<a href="{{ post.url }}">{{ post.data.title }}</a> - <time>{{ post.date.toLocaleDateString() }}</time>
</li>
{%- endfor -%}
</ul>
Let's quickly dissect that loop:
{%- for post in collections.posts -%}: This starts a loop. It basically says, "For each item in thecollections.postsarray, temporarily call itpostand do the following..."{{ post.url }}: Eleventy automatically gives each page a handyurlproperty. We use this for the link'shref.{{ post.data.title }}: Remember the front matter? Eleventy sticks all of that inside adataobject. Sopost.data.titleis how we grab the title from each post's front matter.{{ post.date.toLocaleDateString() }}: Thedatewe put in the front matter is converted into a full-fledged JavaScript Date object, so we can use helpful methods liketoLocaleDateString()on it.{%- endfor -%}: And this, of course, ends the loop.
Save the file and navigate your browser to http://localhost:8080/blog/. You should now see a neat, linked list of your two blog posts! Click on one, and it takes you to the full post page.
Just pause for a second and appreciate what just happened. You wrote content in plain text files, organized them in a folder, and with a few simple lines of templating logic, you created a fully functional blog index. There's no database, no complex backend. Just files and a little bit of build-time magic.
Step 6: The Grand Finale - Going Live!
This is the moment of truth. A website isn't really real until it's on the internet for everyone to see.
First, we need to put our code somewhere that a hosting service can find it. The standard way to do this is with Git, hosted on a platform like GitHub. I'll assume you have Git installed.
Go ahead and stop the Eleventy server with Ctrl + C in your terminal. Then, initialize a Git repository:
git init
git add .
git commit -m "Initial commit of my awesome 11ty site"
Next, pop over to GitHub, create a new repository (don't initialize it with a README), and follow their instructions to push your existing repository from the command line.
Now, for the really fun part: deployment. We'll use Netlify, a platform that has completely revolutionized static site hosting.
- Sign up for a free Netlify account. It's easiest if you just sign up with your GitHub account.
- Once you're on your dashboard, click "Add new site" -> "Import an existing project."
- Connect to GitHub and authorize Netlify to access your repositories.
- Select the repository you just created for your blog.
- Now, Netlify is smart. It will likely detect that you're using Eleventy and pre-fill the build settings for you. They should look like this:
- Build command:
npx @11ty/eleventy - Publish directory:
_site
- Build command:
- Click "Deploy site."
And... that's it. No, really. I'm not kidding.
Netlify will pull your code from GitHub, run the npx @11ty/eleventy command to build your site, and then deploy the resulting _site folder to its global CDN. The whole process usually takes less than a minute.
Once it's done, Netlify will give you a random URL (something like quirky-babbage-12345.netlify.app). Click it.
There it is. Your site. Live on the internet. Built from Markdown files. Blazing fast. Secure.
And here's the best part: from now on, every time you git push a change to your GitHub repository, Netlify will automatically see the change, rebuild your site, and deploy the new version. This workflow is the core of what people call the Jamstack (JavaScript, APIs, and Markup), and it's an incredibly powerful and efficient way to build for the modern web.
Where to Go From Here?
We've really only scratched the surface, but you've already mastered the fundamental workflow of a static site generator. You've gone from zero to a live, auto-deploying blog. That's huge!
From here, the possibilities are endless:
- Styling: We referenced a
/css/style.cssfile in our layout, but we never actually created it. You can add CSS just like you would on any other website. Eleventy has a handy feature called "passthrough copy" to move assets like CSS, images, and fonts from your source folder to the final_sitefolder. - Data Files: Eleventy can slurp up data from JSON or JavaScript files that you store in a
_datadirectory, making that data globally available. This is perfect for things like site navigation or author information. - More Complex Collections: You can do amazing things with collections, like filtering your posts by tags or creating custom sorting logic.
- Serverless Functions: For those little bits of dynamic functionality—like a contact form or a newsletter signup—you can use serverless functions (which services like Netlify also offer) to add that functionality without needing a traditional backend server.
The web is your canvas. Static site generators just give you a simpler, faster, and more enjoyable set of brushes. You're no longer fighting with your tools; you're working with them. You're back to that original dream—focusing on your content and sharing it with the world.
So go on, write that next post. Build that portfolio. The hard part is already over.
Frequently Asked Questions
What is the "Jamstack" I keep hearing about? You've probably heard this buzzword, "Jamstack," floating around. It's really just a name for an architectural approach, not a specific technology. It stands for JavaScript, APIs, and Markup. The "Markup" is your pre-built static site (exactly what we just made!). The "JavaScript" runs on the client-side to add interactivity. And "APIs" are how you connect to services or serverless functions to handle any dynamic parts. Our Eleventy + Netlify site is a perfect, real-world example of a Jamstack site.
Can I use a static site for a large, complex website like an e-commerce store? Absolutely! But you'd tackle it a bit differently. The "storefront" itself (product pages, categories) can be a pre-built static site, which makes browsing incredibly fast for your customers. The dynamic parts—like the shopping cart and the checkout process—are then handled by client-side JavaScript that talks to third-party APIs (like Stripe for payments or Shopify's API for inventory). This hybrid model gives you the best of both worlds: the speed of static with the power of dynamic.
Is this better than WordPress? Ah, the classic question. The honest answer is that it's not about which one is "better" overall, but which one is "better for the job" you're trying to do. For blogs, portfolios, documentation sites, and marketing websites, an SSG is often faster, more secure, and cheaper. For a site that requires a complex, multi-user dashboard for non-technical users to manage intricate content, a traditional CMS like WordPress might still be the right choice. But for a huge portion of the web, SSGs are an absolutely fantastic fit.
What if I need a contact form? That's a great question, and you might think you need a server for that, but you don't! Most modern hosting platforms (like Netlify) offer built-in form handling. You just add a special attribute to your HTML
<form>tag, and their service will process the submissions for you and notify you via email or Slack. It's just another piece of the puzzle that has been solved in the Jamstack ecosystem.