Neon

Give a published site a Postgres database of your own on Neon. Its forms are saved, its visitors can create accounts and sign in, and each visitor keeps their own data.

With a Neon account connected, a site published on PopCraft's hosting can keep what its forms are sent in a database of yours. The database is in your Neon account; PopCraft writes to one table in it.

Attach a database

Give a site a Neon database in one click, then read what the form was sent · 0:08
Description

The coming-soon page, published, with its email sign-up marked as a form and a Neon account connected. In the Publish dialog, under Database, New Neon database is clicked: a project named after the site is made in the Neon account and its database attached, and it is listed. Three visitors then sign up on the site (sent by the recording, as the site sends them). Submissions is clicked and a table shows the three, newest first, with when each was sent and its email.

  1. Publish the site.
  2. In the Publish dialog, under Database, click New Neon database. A project named after the site is made in your Neon account and its database attached. A site with accounts gets sign-in turned on with it.
  3. To use a database you have, type in the field below the button: it lists every database of every connected account. Pick one and it is attached.

No Neon account connected yet? Connect Neon connects it and then makes the database, in the same click.

From then on, every form on the site saves what it is sent. Nothing needs republishing: a site that is already online starts saving at once.

Read what was sent

Click Submissions beside the database. Each row is one submission: when, which form, and the fields as sent.

A form is a frame marked as a form; each field is sent under its name. What the form does after sending (go to a thank-you screen, open an overlay) is unchanged.

Templates to start from

These templates have a form that already works. Start from one, publish it, attach a database, and it saves.

TemplateWhat it saves
Coming soon pageAn email sign-up for opening day.
Contact page with a working formName, email, a topic, a message and a newsletter tick box.
Animated launch page with a working waitlistName, email and a goal, on a page that builds itself in.
Animated invitation with a working RSVPWho is coming, how many, dietary notes, a dish to bring.

Each thanks the visitor once the form is sent, whether or not a database is attached.

One account, many databases

A connection is the account. Each file picks its own project and database, so several sites can use one Neon connection and keep their data apart. The project's default branch is the one used.

What PopCraft does in your database

CreatesOne table, popcraft_submissions (id, form, data as JSON, created_at), and one index. Only if they are not there.
WritesOne row per form sent.
ReadsThat table, when you open Submissions.
Leaves aloneEverything else in the database.
KeepsThe database's connection string, encrypted, to reach it. It is never shown or returned.

The data is yours: query it in Neon, join it, export it.

SELECT created_at, data->>'email' AS email FROM popcraft_submissions WHERE form = 'Waitlist' ORDER BY created_at DESC;

What a visitor can do

A form on your site posts to the site's own address. The site host accepts it only when:

  • it comes from the site's own pages;
  • the site that is online has that form;
  • it is within the limits: 50 fields, 5,000 characters a field, 64,000 in all;
  • the visitor is within the rate limit (20 submissions in ten minutes from one address).

A visitor's text is stored as data. It is never run as SQL.

Detach

Click Detach. The site stops saving submissions. The table and its rows stay in your database.

Ask the AI agent

This waitlist form should save the emails. Set that up.

The agent checks what is connected and recommends Neon when a design has a form whose answers should be kept. With no database in mind it makes one named after the site; otherwise it lists the projects and databases and asks which. It asks you to approve before it attaches or creates anything.

ToolWhat it does
attach_databaseAttach a database, or make one (create: true, or createNamed under a project). Asks first.
set_site_sign_inTurn visitor sign-in on or off. Asks first.
get_form_submissionsWhat visitors sent, newest first.

Command line and API

popcraft run --ui integration.submissions --json
curl -H "Authorization: Bearer $POPCRAFT_TOKEN" https://popcraft.app/api/v1/files/KEY/site/database/submissions

Attach a new database named after the site:

curl -X PUT -H "Authorization: Bearer $POPCRAFT_TOKEN" -H "content-type: application/json" \
  -d '{"create": true, "provider": "neon"}' https://popcraft.app/api/v1/files/KEY/site/database

Accounts: let visitors sign in

Turn on Visitors can sign in under the database in the Publish dialog. PopCraft turns on Neon Auth for that database and tells it your site's address. Visitors' accounts are in your database (the neon_auth schema).

A site with sign-in is made of four things, all set in the design panel's Web section:

WhatWhereWhat it does
A sign-up, sign-in or sign-out formForm › Sending itCreates an account from fields named name, email and password; Signs the visitor in with email and password; Signs the visitor out. After sending runs only when it worked.
A page for the right visitorPage › Who it is forSigned-in visitors: anyone else is taken to your sign-in page. Visitors who are not signed in: someone signed in is taken to their home.
Who is thereVariablesMake user/signedIn (true/false), user/userName, user/userEmail and user/signInError (text). The site sets them; bind layers to them to greet a visitor or show why a sign-in failed.
Each visitor's own dataCollections › Each visitor has their ownA list repeated from the collection shows only the signed-in visitor's records. A form kept as a record of it adds to theirs. A form inside a list's copy that Deletes its record removes one, and one that Changes its record sets the fields it sends and leaves the rest: a button with a name and a value sends them with its form, so "Mark done" is a button named done with the value Yes. A list's filter (item_status == "Booked") shows only the records it holds for, so one collection can be several lists, and a tap moves a record from one to another. A number variable data/<collection>Count follows how many they have, and expressions add them up (sumSince("Sessions", "minutes", 6), streak("Checks"): see Variables and logic). A field in a copy whose value is {{item.note}} starts with that record's, so a form there edits it where it is.
A list everyone sharesCollections › They all see each other'sEvery signed-in visitor sees everyone's records (a guest list, a potluck, a team board); each says who added it (item_by) and whether it is the visitor's (item_mine). Only its maker changes or deletes one.
Their own accountForm › Sending itChanges the visitor's name (name), Changes the visitor's password (password, new_password; their other devices are signed out), Deletes the visitor's account (password; what the site kept for them goes with it). Emails a password reset link (email) opens your site's /reset-password page, where a form that Sets a new password from a reset link (new_password) finishes it. The email is sent by the sign-in service; the page answers the same whether or not the address has an account.

The site asks who is signed in before it draws anything, so a returning visitor lands on their own page and a stranger never sees one that is not for them.

What visitors can and cannot reach:

  • A visitor's session is a cookie on your site's own address that no script can read.
  • A signed-in visitor reads, adds, changes and deletes only their own records. Nobody signed in gets nothing.
  • The records in your file are samples for the design. They are part of the published site's files, so do not put anything private in them.
  • PopCraft makes one more table for these records, popcraft_records.

Seven templates show all of it working, each a complete app to start from:

TemplateWhat it shows
Daybreak — a check-in appA visitor's own list, edited in place; a streak, a week and a count worked out from it
Wayfarer — a trip boardOne collection as three columns; a tap moves a card by changing one field
Tempo — a training logBars as long as a record's minutes; totals this week; marking a best
Saffron — a recipe boxA grid of cards coloured by kind; loving one lifts it into its own row
Marginalia — a reading shelfCovers on three shelves; rating a finished book
Kindling — a habit trackerTwo collections: habits, and check-ins counted per habit per day for streaks and a week of marks
Potluck — a shared party boardA collection everyone signed in shares, with who brought what

Every one has sign-up, sign-in, a forgotten-password reset and an account page where the visitor changes their name and password or deletes their account.

Export it, or host it yourself

A static export (a zip, a GitHub push, a Vercel deployment of the static site) does not save its forms: on PopCraft's hosting, the saving is done by the site host. Export the site as a Next.js project instead: it has the same server of its own and reads DATABASE_URL and, with sign-in, SITE_AUTH_KIND=neon-auth and SITE_AUTH_URL (the Neon project's Auth URL). Deployed to a Vercel project that is a destination, those are set for you.

When something goes wrong

What you seeWhat to do
Neon would not let the site's tables be made thereThe database's owner role cannot create tables. Pick another database, or make a new one.
Sign-in will not turn on: Publish the site firstSign-in is set up for the site's address: publish once, then turn it on.
Visitors cannot sign in after the address changedTurn Visitors can sign in off and on: the new address is told to Neon Auth.
This database can no longer be reached: attach it againThe connection was removed or its key withdrawn. Reconnect Neon and attach the database again.

Not yet

  • Lists everyone sees that read from the database (a visitor's own lists do; shared ones are still part of the published site).
  • Signing in with Google or GitHub.