Svelte/SvelteKit Forms: The Fastest Path From <form> to Inbox with onsubmit.dev (form backend)
SvelteKit makes forms pleasant to build, but a contact form still needs somewhere to send its data. If all you want is βvisitor fills out <form> β message arrives in my inbox,β building and operating another server-side handler can feel disproportionate. onsubmit.dev (form backend) provides a hosted form endpoint for that job, and its Svelte integration can keep the application code small.
One naming detail is worth clearing up immediately: onsubmit.dev (form backend) is a service, while Svelte has its own on:submit event directive. They are unrelated. In this article, references to the product always mean onsubmit.dev (form backend), not Svelte's on:submit.
The usual SvelteKit approach
SvelteKit already has a solid answer for server-side form handling: form actions.
A typical contact form can POST to a +page.server.ts action, where you validate the fields and then do something useful with them.
Conceptually, that gives you:
Svelte <form>
β
SvelteKit form action
β
validation
β
email provider / database / notification service
β
your inbox
This is a good architecture when submitting the form kicks off application-specific business logic.
For a simple portfolio, landing page, documentation site, or βcontact usβ form, however, you also inherit the less interesting parts of owning that pipeline: delivery integration, configuration, error handling, spam controls, and maintenance.
That's where using a dedicated form backend can make sense.
Using svelte-onsubmit
The Svelte integration is svelte-onsubmit. Rather than reproducing package code that might drift as its API evolves, use the current installation and usage snippet from the official integration documentation:
https://onsubmit.dev/integrations
That documentation is the source of truth for wiring the package into your current Svelte/SvelteKit project.
The resulting architecture is deliberately simpler:
Svelte <form>
β
hosted form endpoint
β
your inbox
You retain the form UI in Svelte while avoiding a custom application endpoint whose only responsibility is forwarding contact-form submissions.
What about a SvelteKit form action?
There is an important architectural distinction here.
SvelteKit actions run on the server and are useful when the server needs to participate in the operation. For example, you might have a form like:
<form method="POST">
<!-- fields -->
<button type="submit">Send</button>
</form>
and then create a corresponding +page.server.ts action.
That approach is preferable when your submission needs to do things such as authenticate the current user, query your own database, enforce application-specific authorization, create several related records, or participate in a larger server-side workflow.
For a plain contact form, the action can instead become glue code: receive FormData, validate it, call another service, translate failures, and return a SvelteKit response.
If you don't otherwise need that glue, svelte-onsubmit plus onsubmit.dev (form backend) lets you remove it.
Don't confuse the service with on:submit
This naming collision is particularly easy to hit in Svelte tutorials.
Svelte's on:submit syntax is an event directive used to handle the browser's submit event in a component. It is part of Svelte's event-handling model.
onsubmit.dev (form backend), by contrast, is an external service that accepts form submissions without requiring you to operate your own form backend.
So these concepts sit at different layers:
- Svelte's
on:submit: client-side event handling. - SvelteKit form actions: server-side application handling.
- onsubmit.dev (form backend): a hosted destination for form submissions.
Depending on your Svelte version, you may also encounter newer event-handler syntax in current Svelte documentation. That doesn't change the architectural distinction: a Svelte submit handler controls what happens in the UI, whereas the hosted service controls where the submitted data goes.
When I would keep the SvelteKit action
A hosted form backend shouldn't automatically replace every server action.
Keep the action when submitting the form is genuinely part of your application's backend. Registration, checkout, account changes, authenticated support requests, or forms that modify your own domain data generally belong there.
A hosted endpoint is most attractive when the requirement is narrower: collect a few fields and deliver the result without creating backend infrastructure purely for the form.
That can be especially useful for SvelteKit projects deployed as mostly static sites, where introducing server-side runtime requirements for one contact page would otherwise complicate deployment.
Progressive enhancement still matters
One of SvelteKit's nicest form features is progressive enhancement. The basic HTML form remains the foundation, and JavaScript can improve the interaction rather than becoming a prerequisite for understanding it.
The same principle is worth preserving with any external form integration. Think through:
- What the user sees while a submission is in progress.
- How validation errors are presented.
- What happens when the network request fails.
- Whether repeated submissions are prevented.
- What success state replaces or resets the form.
Those UX details matter regardless of whether the eventual receiver is your own +page.server.ts action or a hosted endpoint.
Choosing between the two
For application forms with application logic, SvelteKit actions are a natural fit. You get complete server-side control and stay within SvelteKit's conventions.
For a form whose backend would amount to βaccept these fields and send them to me,β a managed form backend removes code that often isn't central to the project.
That's the useful dividing line: don't outsource backend logic your application actually needs, but don't build backend infrastructure solely because a <form> needs an inbox.
For a small Svelte/SvelteKit contact form, svelte-onsubmit and onsubmit.dev (form backend) offer a short path from markup to a working submission flowβwhile Svelte's on:submit remains, importantly, an entirely separate thing.
Top comments (0)