How to Deploy a Jekyll Site to Netlify (Complete 2026 Guide)
Everything you need to deploy Jekyll to Netlify — netlify.toml setup, build environment, custom domains, redirects, Netlify Forms, and environment variables.
Netlify was the platform that made deploying static sites simple and it remains one of the best choices for Jekyll in 2026. Automatic deploys from Git, preview URLs for every pull request, built-in form handling, serverless functions, and a generous free tier make it a strong option for everything from personal blogs to production sites.
Why Netlify for Jekyll
- Git-based deploys — push to GitHub, GitLab, or Bitbucket and Netlify builds automatically
- Preview deployments — every pull request gets a unique live preview URL
- Netlify Forms — handle contact form submissions without a backend
- Netlify Functions — add serverless API endpoints alongside your static site
- Free tier — 100GB bandwidth/month, 300 build minutes/month, unlimited sites
- Split testing — A/B test different branches of your site
Prerequisites
- A Jekyll site in a GitHub, GitLab, or Bitbucket repository
- A
Gemfileand committedGemfile.lockin your repo - A Netlify account (free at netlify.com)
Step 1: Prepare your repository
Ensure your repository has a Gemfile:
source "https://rubygems.org"
gem "jekyll", "~> 4.3"
gem "jekyll-feed"
gem "jekyll-seo-tag"
gem "jekyll-sitemap"
Generate and commit Gemfile.lock:
bundle install
git add Gemfile.lock
git commit -m "Add Gemfile.lock for Netlify"
git push
Step 2: Create a netlify.toml file
The netlify.toml file in your repository root controls every aspect of your Netlify build. Create it now:
[build]
command = "jekyll build"
publish = "_site"
[build.environment]
JEKYLL_ENV = "production"
RUBY_VERSION = "3.2.2"
# Production context — runs on pushes to main
[context.production]
command = "jekyll build"
# Deploy preview context — runs on pull requests
[context.deploy-preview]
command = "jekyll build --drafts"
# Branch deploy context — runs on other branches
[context.branch-deploy]
command = "jekyll build"
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-Content-Type-Options = "nosniff"
Commit this file to your repository.
Step 3: Connect to Netlify
- Go to app.netlify.com and log in
- Click Add new site → Import an existing project
- Choose your Git provider (GitHub, GitLab, or Bitbucket) and authorise Netlify
- Select your Jekyll repository
- Netlify detects
netlify.tomland pre-fills the build settings
Review the settings:
- Build command:
jekyll build - Publish directory:
_site
Click Deploy site. Netlify runs the build and your site is live at a URL like random-name-123456.netlify.app.
Step 4: Configure environment variables
For sensitive values (API keys, Sendy list IDs) that should not be in your repository, add them in the Netlify UI:
- Go to Site configuration → Environment variables → Add a variable
- Add key-value pairs
In your Jekyll code, reference them as normal site.* config values. To inject Netlify environment variables into Jekyll at build time, use _config.yml overrides:
# In netlify.toml — pass env var to Jekyll config
[build]
command = "jekyll build --config _config.yml,_config.production.yml"
Create _config.production.yml to merge at build time:
# _config.production.yml — overrides for Netlify production builds
url: "https://jekyllhub.com"
baseurl: ""
Step 5: Set up a custom domain
Option A: Use a domain already with Netlify DNS
- Go to Domain management → Add a domain → enter your domain
- Netlify provisions SSL automatically
Option B: Use a domain registered elsewhere Add a CNAME record with your domain registrar:
- Name:
www - Value:
your-site.netlify.app
For the root domain (@), use an ANAME or ALIAS record pointing to your-site.netlify.app. Not all registrars support ALIAS — Netlify DNS does, and it is free to use.
Redirects with Netlify
Create a _redirects file in your Jekyll source root:
# Redirect non-www to www (or vice versa — pick one)
https://www.jekyllhub.com/* https://jekyllhub.com/:splat 301!
# Redirect old blog URLs
/2025/:month/:day/:slug/ /blog/:slug/ 301
# Proxy an API endpoint (useful for analytics or forms)
/api/* https://your-api.example.com/:splat 200
# Custom 404
/* /404.html 404
Add to _config.yml so Jekyll copies it to _site/:
include:
- _redirects
Netlify processes _redirects at the CDN level — no server involved.
Using Netlify Forms with Jekyll
Netlify Forms let you collect form submissions without a backend. Add a netlify attribute to any HTML form:
<!-- _includes/contact-form.html -->
<form name="contact" method="POST" data-netlify="true" netlify-honeypot="bot-field">
<input type="hidden" name="form-name" value="contact">
<!-- Honeypot field (hidden) -->
<div style="display:none">
<input name="bot-field">
</div>
<label>Name <input type="text" name="name" required></label>
<label>Email <input type="email" name="email" required></label>
<label>Message <textarea name="message" required></textarea></label>
<button type="submit">Send Message</button>
</form>
Netlify detects the data-netlify="true" attribute during the build and wires up form handling. Submissions appear in Forms in your Netlify dashboard, and you can set up email notifications.
Build minutes and the free tier
Netlify’s free tier includes 300 build minutes per month. A typical Jekyll build takes 30–60 seconds, so you have roughly 300–600 deploys per month before any charges.
To reduce build time, add caching to netlify.toml:
[build]
command = "jekyll build"
publish = "_site"
[build.environment]
BUNDLE_PATH = "vendor/bundle"
JEKYLL_ENV = "production"
The BUNDLE_PATH = "vendor/bundle" setting caches your Ruby gems between builds — cutting build time from ~60 seconds to ~10 seconds after the first build.
Deploy with the Netlify CLI
For local testing or CI deployments:
npm install -g netlify-cli
netlify login
netlify deploy --dir=_site --prod
The --prod flag deploys to production. Without it, Netlify creates a draft preview URL.
Useful Netlify features for Jekyll sites
Branch deploys: Any branch pushed to GitHub can have its own Netlify URL. Enable in Site configuration → Build & deploy → Branch deploys.
Deploy notifications: Get a Slack or email notification when deploys succeed or fail. Set up in Site configuration → Build & deploy → Deploy notifications.
Analytics: Netlify Analytics (paid, $9/month) gives server-side analytics with no JavaScript required — accurate data that ad blockers cannot hide.
Large Media: Store large image files in Git LFS and serve them via Netlify’s CDN — keeps your repository size manageable.
Troubleshooting
Bundler::GemNotFound during build
Commit Gemfile.lock and ensure the Ruby version in netlify.toml matches your local environment.
Build succeeds but styles are missing
Check url and baseurl in _config.yml. For a root-domain Netlify site, baseurl should be empty ("").
Form submissions not appearing
Ensure data-netlify="true" is on the <form> tag and the hidden form-name input matches the form’s name attribute. Jekyll must build the page (not exclude it) for Netlify to detect the form.
Redirect loops
Avoid redirecting both www → non-www and non-www → www. Pick one canonical form and redirect only from the other.
Netlify’s balance of simplicity, features, and a generous free tier makes it one of the top choices for Jekyll hosting. The netlify.toml file gives you reproducible, version-controlled build configuration — the same way your Jekyll config works.
Netlify Forms: adding contact forms without a backend
One of Netlify’s most useful features for Jekyll sites is built-in form handling. By adding a netlify attribute to any HTML form in your Jekyll templates, Netlify intercepts form submissions and stores them in its dashboard — with email notifications to your address on every submission. No server-side code, no API integration, no third-party form service account required.
The implementation is minimal: add netlify to your form element and ensure the form has a name attribute. Netlify detects the form during the build process and sets up the submission endpoint automatically. Spam filtering via Netlify’s built-in honeypot or Turnstile CAPTCHA is configurable in the form settings without code changes.
For Jekyll contact pages, this is the cleanest implementation available. The form is a standard HTML form in your _includes/contact-form.html; no JavaScript is required for submission; and the resulting form is accessible and progressively enhanced. If Netlify’s form handling reaches its free tier limit (100 submissions per month), upgrading to the Pro plan or switching to Formspree costs $9-25/month — reasonable for a business site.
Netlify Split Testing for Jekyll content experiments
Netlify’s split testing feature lets you serve different versions of your Jekyll site to different visitors — testing a new homepage design, different call-to-action copy, or alternative content structures. For static sites, this is significantly harder to implement than on dynamic sites, making Netlify’s built-in solution particularly valuable.
Split tests in Netlify work at the branch level. You maintain multiple branches of your Jekyll site (for example, main and test-new-homepage), configure the split test in Netlify’s dashboard with the percentage of traffic each branch should receive, and Netlify routes visitors to the appropriate version transparently. Each visitor is consistently sent to the same branch across their session.
Combining Netlify split testing with a lightweight analytics tool like Plausible or Google Analytics lets you measure the impact of changes on conversion rates, time on site, and page depth. This data-driven approach to Jekyll site optimisation is typically only available to sites with server-side rendering or commercial A/B testing platforms — Netlify brings it to static sites.
Deploy previews and collaborative review on Netlify
Netlify’s deploy preview feature is one of the most valuable workflow improvements available for Jekyll teams. Every pull request to your repository triggers an automatic preview deployment at a unique URL — deploy-preview-42--yoursite.netlify.app. This URL is posted as a comment on the pull request, making it trivially easy for reviewers to see exactly what a proposed change looks like before merging.
For teams with non-technical stakeholders — a client who needs to approve a design change, a marketing manager who needs to verify copy before it goes live — deploy previews eliminate the need to set up a staging environment or explain how to view changes locally. Send the preview URL, get feedback, iterate, and merge only when everyone is satisfied.
Deploy previews are also valuable for catching regressions that are invisible in code review. A Liquid template error, a SCSS breakpoint issue, or a layout problem caused by unusually long content becomes immediately visible in the preview — whereas reviewing the template files in a pull request diff might not reveal the problem at all.
Environment-specific configuration with Netlify
Netlify’s environment variable system allows you to maintain different Jekyll configurations for different environments without putting sensitive values in your repository. Set JEKYLL_ENV=production in Netlify’s build environment variables to ensure analytics tags, cookie banners, and production-only features are included in the built site.
For values like API keys, analytics IDs, and form endpoints that should not be in your repository, use Netlify environment variables to inject them during the build. In your Jekyll _config.yml, reference them as shell variables: analytics_id: <%= ENV['ANALYTICS_ID'] %> — though note this requires the jekyll-config-env gem or a custom build script to process. Alternatively, keep non-secret configuration values (like analytics IDs) in _config.yml and use the environment variable only for genuinely sensitive secrets.
The combination of version-controlled configuration in netlify.toml, environment-specific secrets in Netlify’s environment variables, and Jekyll’s production environment guard ({% if jekyll.environment == 'production' %}) gives you a clean, secure configuration architecture that works consistently across local development, preview deployments, and production.
Netlify’s combination of instant global CDN, free SSL, automatic deploy previews, and a well-documented build pipeline makes it one of the best Jekyll hosting platforms available. For most personal blogs, portfolios, and small business sites, the free Starter plan handles everything you need without ever requiring an upgrade. Start there, configure your build settings, connect your domain, and focus on creating content — the hosting infrastructure will take care of itself.