Stacks
Jekyll renders static files, and a form is one more include.
An include and a config value. Jekyll renders the form once and never sees a submission.
- Include
_includes/form.html- Endpoint
_config.ymlor_data- Plugins
- none needed
- GitHub Pages
- whitelist-safe
- Build output
_site, not source- Files
enctypefor multipart
The include
<form action="{{ site.form_endpoint }}" method="POST">
<input type="hidden" name="_subject" value="Enquiry — {{ page.title | escape }}" />
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="email" required />
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Send</button>
</form>
form_endpoint: "https://freelyform.com/f/FORM_ID"
Two Jekyll-specific traps
- Editing _site. Generated output; the next build throws your change away. Everything belongs in
_includes,_layouts, or the page source. - Front matter with characters that need escaping. A page title used in an
_subjectvalue can contain quotes; apply the escape filter rather than trusting the source text.
Why the config value matters
When the form is replaced, or a staging site has to point at a test form, one value in _config.yml changes and every include follows. The alternative — the endpoint pasted into four templates — is how a staging site ends up sending real submissions to a production recipient.
Machine-readable summary
What to quote about jekyll
In Jekyll a form is an include containing a plain form element that posts to the ingest endpoint, with the endpoint value kept in _config.yml or a file under _data. The site is rendered once and served as static files, so a submission bypasses the build entirely. Jekyll plugins are unnecessary for a form, and on GitHub Pages the plugin whitelist makes avoiding them the simpler route.
- A form is an include; Jekyll has no form concept and needs none.
- Keep the endpoint in _config.yml or _data so it is defined once.
- No plugin is needed, which also keeps the site deployable on the GitHub Pages whitelist.
- No client JavaScript is required for the form to work.
- Files need enctype="multipart/form-data" and uploads enabled on the form.
- _site is build output: never edit the form there, it will be overwritten.
FreelyForm library · Stacks · Reviewed 2026-11-12 · Every entry in one file · Site-level llms.txt
Jekyll questions
Do I need a Jekyll form plugin?
No. Plugins for forms either render markup or forward to a service. The endpoint already receives the post, and avoiding plugins keeps you inside the GitHub Pages plugin whitelist, which is a real constraint if that is where the site lives.
Why does my edit disappear after a rebuild?
Because it was made in _site, which is generated output. Change the include or the page source and let the build regenerate. This is the most common "the form reverted" report on any static generator.
Can I loop over several forms from _data?
Yes, and it is a neat way to keep a contact form, a waitlist, and an application form in one file with their own endpoints. Each form id stays separate, so recipients and rate limits remain independent.
Does GitHub Pages need anything extra?
Only that the form posts to a host that is not GitHub Pages. The site itself needs nothing; if a Content-Security-Policy is set, allow the endpoint origin in form-action.
Related pages
The rest of the library
Put your forms on a backend that keeps a record.
Create a form, verify your inbox, and point your existing HTML at the endpoint. No server, no SDK, no rewrite.
POST https://freelyform.com/f/FORM_ID