FormWire for Hugo

Hugo contact forms, no runtime required.

Hugo builds HTML and gets out of the way — which is exactly what a form needs. Point a plain form at one endpoint and every submission becomes an email in your inbox and a record in your dashboard, while your site stays the pile of fast static files it already is.

Copy-paste code

A partial for layouts, a shortcode for content.

Hugo has no runtime, so the plain HTML POST isn't a fallback here — it's the integration. Build the form once as a partial, expose it to content authors as a shortcode, and keep the key in site params.

<!-- layouts/partials/contact-form.html
     Hugo executes this at build time and ships plain HTML. The browser's
     POST to the endpoint is the entire integration. -->
<form action="https://api.formwire.com/submit" method="POST">
  <input type="hidden" name="access_key" value="{{ site.Params.formwireKey }}">

  <!-- Hugo can't redirect after a POST, so FormWire does. absURL turns
       thanks/ into a full URL using baseURL from hugo.toml. -->
  <input type="hidden" name="_redirect" value="{{ "thanks/" | absURL }}">

  <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</button>
</form>

Swap YOUR-ACCESS-KEY for your form's key in hugo.toml. The full field and response reference lives in the docs at /docs/.

Hugo gotchas

The four things that trip up Hugo forms.

Go templates have sharp edges you only meet once. The snippets above already account for all four.

Template code runs inside HTML comments

Go template actions are parsed everywhere — a {{ partial }} call you "commented out" with <!-- --> still executes at build time, and inside the partial itself it recurses until the build dies. Disable template code with {{/* */}} comments, never HTML ones.

Everything dynamic resolves at build

Hugo has no server at request time, so the key, the redirect URL and every field name are baked into the HTML when the site builds. That's a feature: the browser POSTs straight to the endpoint, and there's nothing on your side to keep alive, patch or scale.

absURL is only as good as baseURL

Hugo's default baseURL is https://example.org/ — leave it unset and your _redirect politely sends every visitor there after they submit. Set baseURL in hugo.toml (and per environment if staging differs) before trusting any absURL output.

Keep the key in site params

Hardcoding the access key in a partial and again in a shortcode drifts the moment you rotate it. Read site.Params.formwireKey in both and the key lives in one line of hugo.toml — safe to commit, since it can only deliver to inboxes you've verified.

Three steps

From nothing to a working form.

  1. Grab your access key

    Create a form in the dashboard and copy its public key into [params] in hugo.toml. It's a safe-to-commit alias for your verified email.

  2. Add the partial, place it once

    Save contact-form.html under layouts/partials and render it with one line in a layout — or expose it as a shortcode so Markdown authors can place it themselves.

  3. Submissions land in your inbox

    Every POST arrives as a formatted email with Reply-To set to the visitor, and as a searchable record in your dashboard.

Why FormWire for Hugo

Built for a site with no runtime.

Works with any theme

Partials in your project's layouts directory override the theme's without forking it, so the form drops into Ananke, PaperMod or your own theme the same way.

Spam filtered without JavaScript

The honeypot runs server-side at the endpoint, so a script-free Hugo site keeps bots out of your inbox — and a captcha is one dashboard toggle away if a form gets targeted.

Nothing added to the build

The integration is a partial and a config param. Your hugo command, your CI and your deploy stay byte-for-byte the same.

Every submission stored

Beyond the email, each POST becomes a searchable record with CSV export and a JSON read API — the paper trail a static site otherwise can't keep.

Hugo form FAQ

The questions Hugo developers actually ask.

Building with another framework?

See all frameworks
Ready in a minute

Ship your Hugo form today.

Grab an access key, paste a partial, and route submissions to your inbox — or on to Slack, Sheets and Zapier.

Free tier forever. No credit card required.