{"id":293530,"date":"2019-08-02T07:13:18","date_gmt":"2019-08-02T14:13:18","guid":{"rendered":"https:\/\/css-tricks.com\/?p=293530"},"modified":"2020-01-14T10:41:01","modified_gmt":"2020-01-14T17:41:01","slug":"using-netlify-forms-and-netlify-functions-to-build-an-email-sign-up-widget","status":"publish","type":"post","link":"https:\/\/css-tricks.com\/using-netlify-forms-and-netlify-functions-to-build-an-email-sign-up-widget\/","title":{"rendered":"Using Netlify Forms and Netlify Functions to Build an Email Sign-Up Widget"},"content":{"rendered":"
Building and maintaining your own website is a great idea. Not only do you own your platform<\/a>, but you get to experiment with web technologies along the way. Recently, I dug into a concept called serverless functions, starting with my own website<\/a>. I\u2019d like to share the results and what I learned along the way, so you can get your hands dirty, too!<\/p>\n <\/p>\n A serverless function (sometimes called a lambda function or cloud function) is a piece of code that you can write, host, and run independently of your website, app, or any other code. Despite the name, serverless functions do, indeed, run on a server<\/a>; but it\u2019s a server you don\u2019t have to build or maintain. Serverless functions are exciting because they take a lot of the legwork out of making powerful, scalable, apps.<\/p>\n There\u2019s lots of great information on serverless functions out there, and a great place to start is CSS Trick\u2019s own guide: The Power of Serverless Front-End Developers<\/a>.<\/p>\n I started my journey with a challenge: I wanted to have an email list sign-up form on my site. The rules are as follows:<\/p>\n My website is built using a static site framework called 11ty<\/a>. 11ty allows me to write templates and components in HTML, so that\u2019s how we\u2019ll build our email form. (Chris recently wrote a great article about his experience with 11ty<\/a> if you\u2019re interested in learning more.)<\/p>\n The website is then deployed using a service called Netlify<\/a>) and it is the key player on our team here: the point guard, the quarterback, the captain. That\u2019s because Netlify has three features that work together to produce serverless excellence:<\/p>\n Finally, I\u2019ll manage my email list with a service called Buttondown<\/a>. It\u2019s a no-frills email newsletter provider, with an easy-to-use API<\/abbr>.<\/p>\n Bonus:<\/strong> for personal sites like mine, 11ty, Netlify, and Buttondown are free<\/em>. You can\u2019t beat that.<\/p>\n The HTML for my email subscription form is very minimal, with a few extras for Netlify Forms to work.<\/p>\n First, I set the The first input in the form is named If the form gets submitted with anything in the The next input in the form is named One neat feature of Netlify Forms is the ability to automatically redirect users to a \u201cthank you\u201d page when they submit a form. But ideally, I\u2019d like to keep my users on<\/em> the page. I wrote a short function to submit the form without a redirect.<\/p>\n When I provide the content of my email form to this function via the This function is called whenever a user clicks the \u201csubmit\u201d button on the form:<\/p>\n This listener progressively enhances<\/em> the default behavior of the form. This means that if the user has JavaScript disabled, the form still works!<\/p>\n Now that we have a working email submission form, it\u2019s time to do some automation with a serverless function.<\/p>\n The way Netlify functions work is as follows:<\/p>\n That\u2019s it! The next time you deploy your site, the function will be ready to go.<\/p>\n The function for my site is going to be in the functions folder, so I have the following in my Then, I\u2019ll add a file in the functions folder called submission-created.js. It\u2019s important to name the file submission-created<\/strong> so that Netlify knows to run it every time a new form submission occurs. A full list of events you can script against can be found in Netlify\u2019s documentation<\/a>. If you\u2019ve correctly named and configured your function, you should see it on Netlify\u2019s Functions dashboard:<\/p>\n The content in submission-created.js looks like this:<\/p>\n Let\u2019s look at this line-by-line.<\/p>\n Line 1 includes a library called On line 2, I add a small library called On line 3, I import my API<\/abbr> key from the environment variables object, Line 4 is where the function is defined. The After retrieving the email address from the The body of my POST request consists of the email address we retrieved.<\/p>\n Then (using the neat Now that I\u2019ve written my function, configured my netlify.toml file, and added my environment variables, everything is ready to go. Deploying is painless: just set up Netlify\u2019s GitHub integration, and your function will be deployed when your project is pushed.<\/p>\n Netlify projects can also be tested locally using Netlify Dev<\/a>. Depending on the complexity of your code, it can be faster to develop locally: just run Buttondown\u2019s API<\/abbr> has a few possible responses when I submit a new email. For instance, if a user submits an email that\u2019s already subscribed to the list, I\u2019d love to be able to tell them as soon as they submit the form.<\/p>\n All in all, I only had to write about 50 lines of code to have a functional email newsletter sign-up form available on my website. I wrote it all in HTML, CSS, and JavaScript, without having to fret with the server side of the equation. The form handles spam, and my readers get a nice experience whether they have JavaScript enabled or not.<\/p>\n","protected":false},"excerpt":{"rendered":" Building and maintaining your own website is a great idea. Not only do you own your platform, but you get […]<\/p>\n","protected":false},"author":263433,"featured_media":293773,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"inline_featured_image":false,"c2c_always_allow_admin_comments":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_share_on_mastodon":"0","_share_on_mastodon_status":"%title% %permalink%"},"categories":[4],"tags":[595,1415,3126,1024],"class_list":["post-293530","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-articles","tag-forms","tag-netlify","tag-netlify-functions","tag-serverless"],"acf":{"show_toc":"No"},"share_on_mastodon":{"url":"","error":""},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/netlify-icons.png?fit=1200%2C600&ssl=1","jetpack-related-posts":[{"id":270959,"url":"https:\/\/css-tricks.com\/forms-auth-and-serverless-functions-on-gatsby-and-netlify\/","url_meta":{"origin":293530,"position":0},"title":"Forms, Auth and Serverless Functions on Gatsby and Netlify","author":"Maxime Laboissonni\u00e8re","date":"May 31, 2018","format":false,"excerpt":"Abstracting infrastructure is in our DNA. Roads, schools, water supply networks\u2014you get the idea. Web development is no exception: serverless architectures are a beautiful expression of that phenomenon. Static sites, in particular, are turning into dynamic, rich experiences. Handling static forms, authentication, and backend functions on statically-generated sites is now\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/gatsby-netlify.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/gatsby-netlify.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/gatsby-netlify.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/gatsby-netlify.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2018\/05\/gatsby-netlify.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":295701,"url":"https:\/\/css-tricks.com\/static-first-pre-generated-jamstack-sites-with-serverless-rendering-as-a-fallback\/","url_meta":{"origin":293530,"position":1},"title":"Static First: Pre-Generated JAMstack Sites with Serverless Rendering as a Fallback","author":"Phil Hawksworth","date":"September 23, 2019","format":false,"excerpt":"You might be seeing the term JAMstack popping up more and more frequently. I\u2019ve been a fan of it as an approach for some time. One of the principles of JAMstack is that of pre-rendering. In other words, it generates your site into a collection of static assets in advance,\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/09\/lollies.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/09\/lollies.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/09\/lollies.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/09\/lollies.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/09\/lollies.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":325374,"url":"https:\/\/css-tricks.com\/netlify-background-functions\/","url_meta":{"origin":293530,"position":2},"title":"Netlify Background Functions","author":"Chris Coyier","date":"November 10, 2020","format":false,"excerpt":"As quickly as I can: AWS Lambda is great: it allows you to run server-side code without really running a server. This is what \"serverless\" largely means.Netlify Functions run on AWS Lambda and make them way easier to use. For example, you just chuck some scripts into a folder they\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/background-functions.png?fit=1200%2C832&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/background-functions.png?fit=1200%2C832&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/background-functions.png?fit=1200%2C832&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/background-functions.png?fit=1200%2C832&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/11\/background-functions.png?fit=1200%2C832&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":316097,"url":"https:\/\/css-tricks.com\/building-serverless-graphql-api-in-node-with-express-and-netlify\/","url_meta":{"origin":293530,"position":3},"title":"Building Serverless GraphQL API in Node with Express and Netlify","author":"Matthew Str\u00f6m","date":"July 6, 2020","format":false,"excerpt":"I\u2019ve always wanted to build an API, but was scared away by just how complicated things looked. I\u2019d read a lot of tutorials that start with \u201cfirst, install this library and this library and this library\u201d without explaining why that was important. I\u2019m kind of a Luddite when it comes\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/07\/graphql-express-netlify.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/07\/graphql-express-netlify.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/07\/graphql-express-netlify.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/07\/graphql-express-netlify.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2020\/07\/graphql-express-netlify.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":292959,"url":"https:\/\/css-tricks.com\/lets-build-a-jamstack-e-commerce-store-with-netlify-functions\/","url_meta":{"origin":293530,"position":4},"title":"Let’s Build a JAMstack E-Commerce Store with Netlify Functions","author":"Sarah Drasner","date":"August 20, 2019","format":false,"excerpt":"A lot of people are confused about what JAMstack is. The acronym stands for JavaScript, APIs, and Markup, but truly, JAMstack doesn\u2019t have to include all three. What defines JAMstack is that it\u2019s served without web servers. If you consider the history of computing, this type of abstraction isn\u2019t unnatural;\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/ecommerce-demo.png?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/ecommerce-demo.png?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/ecommerce-demo.png?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/ecommerce-demo.png?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2019\/08\/ecommerce-demo.png?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":340465,"url":"https:\/\/css-tricks.com\/serverless-functions-the-secret-to-ultra-productive-front-end-teams\/","url_meta":{"origin":293530,"position":5},"title":"Serverless Functions: The Secret to Ultra-Productive Front-End Teams","author":"Jason Lengstorf","date":"May 31, 2021","format":false,"excerpt":"Modern apps place high demands on front-end developers. Web apps require complex functionality, and the lion's share of that work is falling to front-end devs: building modern, accessible user interfacescreating interactive elements and complex animationsmanaging complex application statemeta-programming: build scripts, transpilers, bundlers, linters, etc.reading from REST, GraphQL, and other APIsmiddle-tier\u2026","rel":"","context":"In "Articles"","block_context":{"text":"Articles","link":"https:\/\/css-tricks.com\/category\/articles\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/05\/netlify-serverless-function-rest-api.jpg?fit=1200%2C600&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/05\/netlify-serverless-function-rest-api.jpg?fit=1200%2C600&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/05\/netlify-serverless-function-rest-api.jpg?fit=1200%2C600&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/05\/netlify-serverless-function-rest-api.jpg?fit=1200%2C600&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/css-tricks.com\/wp-content\/uploads\/2021\/05\/netlify-serverless-function-rest-api.jpg?fit=1200%2C600&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/293530","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/users\/263433"}],"replies":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/comments?post=293530"}],"version-history":[{"count":8,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/293530\/revisions"}],"predecessor-version":[{"id":301960,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/posts\/293530\/revisions\/301960"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media\/293773"}],"wp:attachment":[{"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/media?parent=293530"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/categories?post=293530"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/css-tricks.com\/wp-json\/wp\/v2\/tags?post=293530"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}But first, a 1-minute intro to serverless functions<\/h3>\n
The Challenge: Build a Mailing List Sign Up Form<\/h3>\n
\n
Meet the team: 11ty, Netlify, and Buttondown<\/h3>\n
\n
The form<\/h3>\n
<form class=\"email-form\" name=\"newsletter\" method=\"POST\" data-netlify=\"true\" netlify-honeypot=\"bot-field\">\r\n <div hidden aria-hidden=\"true\">\r\n <label>\r\n Don\u2019t fill this out if you're human: \r\n <input name=\"bot-field\" \/>\r\n <\/label>\r\n <\/div>\r\n <label for=\"email\">Your email address<\/label>\r\n <div>\r\n <input type=\"email\" name=\"email\" placeholder=\"Email\" id=\"email\" required \/>\r\n <button type=\"submit\">Subscribe<\/button>\r\n <\/div>\r\n<\/form><\/code><\/pre>\ndata-netlify<\/code> attribute to true<\/code> to tell Netlify to handle this form.<\/p>\nbot-field<\/code>. This tricks robots into revealing themselves: I tell Netlify to watch for any suspicious submissions by setting the netlify-honeypot<\/code> attribute to bot-field<\/code>. I then hide the field from humans using the html hidden<\/code> and aria-hidden<\/code> values \u2014 users with and without assistive technology won\u2019t be able to fill out the fake input. <\/p>\nbot-field<\/code> input, Netlify knows it\u2019s coming from a robot, and ignores the input. In addition to this layer of protection, Netlify automatically filters suspicious submissions with Askimet<\/a>. I don\u2019t have to worry about spam!<\/p>\nemail<\/code>. This is where the email address goes! I\u2019ve specified the input-type as email<\/code>, and indicated that is required<\/code>; this means that the browser will do all my validation for me, and won\u2019t let users submit anything other than a valid email address.<\/p>\n
<\/figure>\nProgressive enhancement with JavaScript<\/h3>\n
const processForm = form => {\r\n const data = new FormData(form)\r\n data.append('form-name', 'newsletter');\r\n fetch('\/', {\r\n method: 'POST',\r\n body: data,\r\n })\r\n .then(() => {\r\n form.innerHTML = `<div class=\"form--success\">Almost there! Check your inbox for a confirmation e-mail.<\/div>`;\r\n })\r\n .catch(error => {\r\n form.innerHTML = `<div class=\"form--error\">Error: ${error}<\/div>`;\r\n })\r\n}<\/code><\/pre>\nform<\/code> value, it submits the form using JavaScript\u2019s built-in Fetch API<\/abbr><\/a>. If the function was successful, it shows a pleasant message to the user. If the function hits a snag, it\u2019ll tell my users that something went wrong.<\/p>\nconst emailForm = document.querySelector('.email-form')\r\nif (emailForm) {\r\n emailForm.addEventListener('submit', e => {\r\n e.preventDefault();\r\n processForm(emailForm);\r\n })\r\n}<\/code><\/pre>\n
<\/figure>\nThe serverless function<\/h3>\n
\n
netlify.toml<\/code> file:<\/p>\n[build]\r\n base = \".\"\r\n functions = \".\/functions\"<\/code><\/pre>\n
require('dotenv').config()\r\nconst fetch = require('node-fetch')\r\nconst { EMAIL_TOKEN } = process.env\r\nexports.handler = async event => {\r\n const email = JSON.parse(event.body).payload.email\r\n console.log(`Recieved a submission: ${email}`)\r\n return fetch('https:\/\/api.buttondown.email\/v1\/subscribers', {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Token ${EMAIL_TOKEN}`,\r\n 'Content-Type': 'application\/json',\r\n },\r\n body: JSON.stringify({ email }),\r\n })\r\n .then(response => response.json())\r\n .then(data => {\r\n console.log(`Submitted to Buttondown:\\n ${data}`)\r\n })\r\n .catch(error => ({ statusCode: 422, body: String(error) }))\r\n}<\/code><\/pre>\ndotenv<\/code>. This will help me use environment variables.<\/strong> Environment variables are useful to hold information that I don\u2019t want to make public, like an API<\/abbr> key. If I\u2019m running my project locally, I set my environment variables with a .env<\/code> file in the repo, and make sure it\u2019s listed my .gitignore<\/code> file. In order to deploy on Netlify, I also set up environment variables in Netlify\u2019s web interface.<\/p>\n
<\/figure>\nnode-fetch<\/code>. This allows me to use Javascript\u2019s Fetch API<\/abbr> in node, which is how we\u2019ll send data to Buttondown. Netlify automatically includes this dependency, as long as it\u2019s listed in my project\u2019s package.json<\/code> file.<\/p>\nprocess.env<\/code>.<\/p>\nexports.handler<\/code> value is where Netlify expects to find our function, so we define it there. The only input we\u2019ll need is the event<\/code> value, which will contain all of the data from the form submission.<\/p>\nevent<\/code> value using JSON.parse<\/code>, I\u2019m ready to send it off to Buttondown. Here\u2019s where I use the node-fetch<\/code> library I imported earlier: I send a POST request to https:\/\/api.buttondown.email\/v1\/subscribers<\/code>, including my API<\/abbr> key in the header. Buttondown\u2019s API<\/abbr><\/a> doesn\u2019t have many features, so it doesn\u2019t take long to read through the documentation if you\u2019d like to learn more.<\/p>\n.then()<\/code> syntax), I collect the response from Buttondown\u2019s server. I do this so I can diagnose any issues that are happening with the process \u2014 Netlify makes it easy to check your function\u2019s logs, so use console.log<\/code> often!<\/p>\n
<\/figure>\nDeploying the function<\/h3>\n
npm i netlify -g<\/code>, then netlify dev<\/code>. Netlify Dev will use the netlify.toml file to configure and run the project locally, including any serverless functions. Neat, right? One caveat: Netlify Dev currently can\u2019t trigger serverless functions on form submissions, so you\u2019ll have to test that using preview builds<\/a>.<\/p>\nAn idea for the future<\/h3>\n
Conclusion<\/h3>\n