The idea is appealing enough that most people try it at least once. The questions are already typed out in a spreadsheet, the options are already in a column, so a form should be producible from the sheet rather than assembled by dragging fields around. It can be. The honest question is whether it is worth the code, and the answer depends almost entirely on how many times the form is going to be built.
What follows is the shape of the problem: what actually can be generated, the four situations where it repays the effort, the situations where it is slower than typing, and the boundary nobody mentions until the first cycle is over.
The direction the tools run in
Two separate things get confused because they use the same two products.
Sending responses into a sheet is a built in destination. The form owns the link, and from the sheet side the association is discoverable: the Apps Script Sheet class has a method that returns the URL of the form whose responses arrive in that sheet, or null when none is attached. That is the well trodden direction.
Building a form out of a sheet's contents is the opposite direction, and there is no built in feature for it. It is a script, an add-on that runs a script, or a program calling the Forms API. All three work, and none of them establishes a live relationship. The sheet is read once, the form is produced, and from that moment the two have nothing to do with each other unless the script is run again.
That is the fact that catches teams out. Editing the option list in the spreadsheet after generation changes nothing in the form. The generated form is output, not a view.
What can be generated
The building blocks are documented and cover nearly every question type a form can hold. In Apps Script, FormApp creates a form and the Form class appends items: single line text, paragraph text, multiple choice, a dropdown list, checkboxes, a grid of rows and columns, date, time, date and time, plus layout items such as page breaks, images, and video. Required flags, help text, and the order of items are all set in code.
A row in a spreadsheet therefore maps onto a question cleanly enough to be mechanical.
| Column in the sheet | What the script does with it |
|---|---|
| Question text | The item title |
| Type, as a keyword such as text or choice | Selects which add method is called |
| Options, separated by a delimiter | The choice values |
| Required, as yes or no | The required flag |
| Help text | The item's description |
| Section | Inserts a page break before this item |
The same shape is available outside Apps Script. The Forms API exposes create, get, batchUpdate, and setPublishSettings on a form, so a service in any language can build and amend a form. Where the choice matters: Apps Script needs no infrastructure and is limited to 6 minutes per execution, while a program using the API runs wherever it is deployed and has to handle its own authentication.
Linking the generated form to a destination is one line in Apps Script, where the form is pointed at a spreadsheet by its identifier. Worth noting that this creates a new tab for responses rather than writing back into the sheet the questions came from. The source sheet and the response sheet are different things, and keeping them in one file is a decision to make deliberately rather than by accident.
The four cases where it pays
Generation is worth the code when the number of items is large, or the number of forms is.
Long option lists that already exist somewhere
A dropdown of 400 product codes, 60 branches, or every course in a catalogue is miserable to type into a form and trivial to read from a column. If the list is already maintained in a sheet because that is where the business keeps it, generation is the correct answer and the argument ends there.
Many forms with the same skeleton
Twelve regional intakes that differ only in the site list and the recipient. A script that loops over a sheet and produces twelve forms guarantees they are identical where they should be identical. Assembling them by hand guarantees at least one will be subtly different, and the difference will be discovered by a respondent.
A form rebuilt every cycle
Course sign ups each term, annual declarations, monthly stock counts. The questions barely change and the options change every time. Regenerating is faster than editing, and it removes the risk of last term's options being left behind in one question.
Options that come from a system of record
Where the list of valid values lives in a database or an inventory system, exporting it into a sheet and generating from there puts the form one step away from the authoritative list rather than three. A scheduled regeneration keeps the drift down to the interval between runs.
Where typing wins
For a single form with a dozen questions, the editor is faster than a script, and it is faster for the second change too. Three things specifically are worse in code.
Layout and tone. A form read by an applicant needs its wording, its help text, and its section breaks tuned by eye. Doing that through a regenerate and reload loop is slow, and the result usually reads like a table rather than like a request.
Conditional paths. Sending respondents down different routes based on an answer is expressible in code and easy to get wrong, because the branching lives in the relationship between page breaks. Building it in the editor once and leaving it alone is more reliable than rebuilding it every run.
Anything with a live form. Regenerating replaces the form, which means a new URL. If the previous link has been emailed, printed, or embedded, the new one has to be distributed again, and the responses collected by both versions now sit in two places.
A rule of thumb that holds up: generate when the form is disposable, and hand build when the link is public and permanent.
An add-on or a script of your own
Both routes end up calling the same building blocks, so the choice is about ownership rather than capability.
An add-on is faster to start with. Somebody else has written the mapping, handled the question types, and produced an interface for choosing which columns mean what. The cost is that the mapping is theirs. When the sheet needs a column the add-on does not recognise, or a question type it never implemented, there is nothing to change. An add-on also asks for authorisation to read the spreadsheet and manage forms, and that grant belongs to whoever installs it, which is worth checking against internal rules before it goes anywhere near a sheet of personal data.
A script written in house is slower to start and cheaper to change. The mapping is visible, the failure messages are readable, and the whole thing is a file in an account that can be handed over. The risk is the ordinary one: it is code that nobody has written tests for, and the person who understands it may not be in the room the next time it fails.
Where a process is going to run for years, the script is usually the better investment. Where somebody needs one large form built this week, the add-on is the proportionate answer, and there is no need to be precious about it.
The maintenance nobody budgets for
Generation introduces a small piece of software into the process, and it inherits the obligations of software.
The script has an owner. It runs under one account's authorisation. When that person leaves, the trigger stops and the failure is silent, because nothing visibly breaks until somebody notices last month's form was never built.
The quotas apply even to modest jobs. Apps Script publishes a limit of 6 minutes per execution, 20 triggers per user per script, and total trigger runtime of 90 minutes a day on a consumer account or 6 hours on a Google Workspace account, all subject to change without notice. A loop building twelve forms with fifty items each is close enough to the execution limit to need batching rather than one long run.
The mapping is a contract. The moment the script reads a Type column, the spelling of the values in that column becomes part of the system. Somebody types Choice instead of choice, or adds a type the script has never heard of, and the run fails or quietly skips items. A validation rule on that column, requiring a value from a fixed list, costs nothing and prevents the most common failure.
There is no test run for free. A generator that produces a live form has to be tried somewhere harmless first, which means a throwaway copy of the source sheet and a form that gets deleted afterwards. Skipping that step is how a half built form reaches respondents, and a form that has already collected three responses cannot be quietly replaced. Keeping a deliberate test path, with the destination pointed at a scratch spreadsheet, turns a risky deployment into a routine one.
The generated form is still a form. It collects answers, and it holds no owner, no status, and no record of the reply. The Forms API reflects this deliberately: responses can be read through get and list, and there is no method to write to a response. Generating the form faster does not touch the work that happens after submission, which is where the hours actually go.
Deciding in one pass
Count two things. How many items the form has, and how many times it will be built this year.
| Items | Times built | Sensible route |
|---|---|---|
| Under 20 | Once | Build it in the editor |
| Under 20 | Every month or term | Duplicate an existing form, or generate |
| Over 50 | Once | Generate, then tune the wording by hand |
| Over 50 | Repeatedly | Generate, with the option list owned by one sheet |
The bottom row is the only case where the script is unambiguously correct. The top row is the case where people write a script anyway, usually because the code is more interesting than the typing.
What to change first
If the option list is long and lives in a sheet already, write the generator and make that sheet the single source for the list. If the form is small and permanent, build it by hand and spend the saved effort on what happens after submission, since that is where a form tool with an owner and a status per response earns its place. The features page and the demo of Halict show that side of the process rather than the building side.
Q1. Is there a built in way to create a Google Form from a spreadsheet?
Sending responses into a sheet is built in, but producing a form from a sheet's contents is not. It requires Apps Script, an add-on that runs a script, or a program calling the Forms API, which exposes create and batchUpdate on a form. None of those creates a live connection, so the sheet is read once at generation time.
Q2. Will the form update when the option list in the spreadsheet changes?
No. The generated form is output, not a view of the sheet. Changing a value in the option column has no effect until the script runs again, which is why teams that need the list to stay accurate put the generator on a schedule and accept drift no larger than the interval between runs.
Q3. Does regenerating the form keep the same link and the same responses?
Regenerating produces a new form with a new URL, and responses already collected stay with the old one. Where the link has been published or printed, editing the existing form is safer than rebuilding it. Where the form is distributed fresh each cycle, the new URL is not a problem at all.
Q4. Which question types can be created from a script?
The documented items cover single line text, paragraph text, multiple choice, dropdown lists, checkboxes, grids, date, time, and date with time, plus layout items such as page breaks, images, and video. Required flags and help text are set in code as well, so the mapping from a spreadsheet row to a question can be fully mechanical.
Q5. What is the most common reason a generator breaks?
The type column. Once a script reads keywords out of a spreadsheet, the spelling of those keywords is part of the system, and a stray capital letter or an unrecognised type either fails the run or skips items silently. Applying a validation rule that requires a value from a fixed list prevents it before the first bad row is typed.
