Guide

A table generator for HTML that brings its own database

Every other tool in this category outputs a <table> string and walks away. mk0r treats it as a three-part job: provision a per-session Neon Postgres project, seed rows, then generate the React component that queries them. The HTML you see is backed by SQL on the first turn.

Generate a table with a backend
m
mk0r
9 min
4.8from 10K+ creators
Per-session Neon project
DATABASE_URL wired from turn one
No signup, no card

What the top results for "table generator for html" actually give you

I read the first five results before writing this. They are near duplicates of each other. You pick row count, column count, border style, padding, maybe a color scheme. You click generate. A string of HTML and CSS appears at the bottom with a copy button. That is the entire product. None of them do any of this:

Create a Postgres table from your descriptionInsert seed rows via real SQLWrite the SELECT query that feeds the cellsWire DATABASE_URL into the running appGenerate a migration file checked into gitLet you edit a row and write back to the databaseHandle the empty state when a query returns no rowsSerialize the final table to inline-styled HTML on demandScale to thousands of rows without re-pasting

A <table> blob is not a table. It is a snapshot of rows you happened to type into a form. The moment you need the 21st row, the shape breaks. mk0r flips the order: database first, query second, HTML third.

What actually runs when you hit the landing page

Before the first prompt, four things get wired up: the Vite dev server, the git repo, the Playwright-capable Chromium, and the Neon Postgres project. Only the last one makes mk0r distinct here.

Your prompt fans out to four live systems

Your description
Column hints
Seed preferences
mk0r sandbox
Neon project
Vite server
Git repo

The Neon path is not a theory. A REST call at POST /api/v2/projects creates a real database, returns a connection URI, and that URI lands in DATABASE_URL inside the sandbox before the agent has written a single line.

The anchor fact: where the database comes from

This is the part no competitor page can copy, because it is wired into the Cloud Run service, not the prompt. When a session spins up, the provisioning layer calls Neon's control plane API and waits for a project. The excerpt below is the function that runs, unmodified.

src/core/service-provisioning.ts (excerpt)

Region is aws-us-east-2, Postgres version 17, project name mk0r-<session>, 30-second timeout. The agent then reads about this database from its CLAUDE.md (rendered at src/core/vm-claude-md.ts line 1273), which documents DATABASE_URL, NEON_HOST, and how to query via @neondatabase/serverless. That is why the agent never asks you for a connection string.

The terminal trace of a single prompt

"Build me a customers table with name, email, plan, and joined date. Seed twenty plausible rows." Here is what the agent runs in the sandbox between your prompt and the rendered HTML.

agent provisions, seeds, and renders

Four artifacts land in the repo from that single turn: the CREATE TABLE migration, the seed script, the React component, and the import line in App.tsx. None of them are throwaway. Every one of them is the kind of file you would write in a production codebase.

What every other table generator for HTML gives you vs. what mk0r writes

Left side: the artifact the top SERP results ship. Right side: the component the agent commits on turn one. Same visual result, entirely different operational footprint.

dead string vs. live component

<!-- copy, paste, hope -->
<table border="1" cellpadding="8" cellspacing="0"
  style="border-collapse:collapse;font-family:sans-serif">
  <thead>
    <tr style="background:#f4f4f5">
      <th>Name</th>
      <th>Email</th>
      <th>Plan</th>
      <th>Joined</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Adeline Okafor</td>
      <td>adeline@acme.io</td>
      <td>Pro</td>
      <td>2026-01-14</td>
    </tr>
    <tr>
      <td>Yolanda Pryor</td>
      <td>yp@acme.io</td>
      <td>Free</td>
      <td>2026-02-02</td>
    </tr>
    <!-- hand-typed. edit a cell = retype it -->
  </tbody>
</table>
-8% fewer lines

Static HTML generators vs. mk0r

FeatureStatic table generator for HTMLmk0r
BackendNonePer-session Neon Postgres project (pg_version 17)
RowsTyped by hand into a formINSERTed via SQL, queried with SELECT
SchemaUnwritten; lives in your headCREATE TABLE statement checked into the repo
Output shapeHTML string you paste somewhereReact component + SQL migration + seed file
Edit a rowFind the cell and retypeUPDATE statement or admin UI the agent adds
Connection stringN/ADATABASE_URL available to the agent from turn one
IterationClick generate, copy, paste, repeatDescribe the change, agent edits schema + component
SignupOften yes (to save tables)No account, no card, anonymous Firebase session

What you get with a backing database

Because the rows live in Postgres, the feature set of the table is the feature set of SQL plus a rendering layer. Here is the surface most sessions end up using.

Backed by real SQL

Rows come from SELECT * FROM <table>, not a hard-coded array. Changing them means INSERT, UPDATE, DELETE. That is the surface area the agent works with for every follow-up prompt.

Schema checked into git

The CREATE TABLE statement gets committed as a migration file, not pasted ephemerally. Every turn that mutates the schema is one more commit you can walk back.

Seed data that looks real

The agent generates 15-25 plausible rows by default. Ask for more, ask for Faker.js, ask for rows scraped from a CSV you paste. The seeds live in src/db/seed.ts.

Queryable from the React component

Tables call the neon() serverless driver with DATABASE_URL. No pooler, no connection manager, no Prisma overhead. Edge-ready from the first prompt.

Editable inline or via a form

Ask for inline contenteditable cells and the agent wires onBlur to an UPDATE query. Ask for a side-panel form and it scaffolds that too. Both write back to Postgres.

Exportable to flat HTML

Ask the agent to 'serialize the current rows to inline-styled HTML for an email'. It reads from Neon, renders, and hands back a static string you can paste anywhere.

The numbers underneath a single session

Three numbers matter more than anything else when you evaluate a table generator for HTML: how many signup steps, how many servers get spun up, and what Postgres version lives behind them.

0Postgres version in every session
0Signup steps before a table exists
0Neon project timeout (seconds)
0Services wired per session
0 rows

Default seed count the agent writes into a new table. Ask for more and the seeds file grows in-place.

0 commit

Per chat turn that touches files. Schema, seeds, and component land together.

0-char slug

From the session key, used to name the Neon project so it never collides with another app's database.

Five prompts from "make a table" to a production-shape feature

1

Describe the columns

'A customers table with name, email, plan, joined date.' The agent writes a CREATE TABLE statement and commits a migration, reusing the existing DATABASE_URL.

2

Seed plausible rows

'Seed twenty rows with realistic names and recent join dates.' A seed script runs, twenty INSERTs land in the provisioned Neon database, and the Vite server refreshes with the new data.

3

Make it editable

'Let me edit the plan cell inline.' The agent adds contenteditable + an onBlur handler that issues an UPDATE query to Postgres. No extra migration needed.

4

Add a filter

'Filter by plan.' A WHERE clause gets added to the SQL template and a select element renders above the table. Playwright types into the select and verifies the row count changes before the turn commits.

5

Export or ship

'Serialize the current rows to inline-styled HTML I can paste into an email.' The agent reads from Neon, generates a portable string, and logs the output to the chat. You paste it wherever you need a static snapshot.

When a dead string is still the right answer

Sometimes you do want the flat HTML that a traditional table generator for HTML produces. A single invoice snapshot embedded in a PDF. A pricing matrix for a WordPress page. A one-off layout for a MailChimp template. For those, the Postgres layer is overhead.

Ask mk0r: "Give me a single HTML file with inline styles for a three-column pricing table. No JavaScript, no database, no Tailwind." The agent drops the Postgres path and outputs exactly that string.

You get portability and you lose iteration. That is the honest trade. The good part is you do not have to switch tools to get either shape: both live inside the same chat.

Need this wired into your own data?

If your table has to query a database you already own, book a quick call and we will point the agent at it live.

Book a 15-min call
Describe a table and watch it build, with a database

Frequently asked questions

Frequently asked questions

Why does mk0r provision a database for something as simple as an HTML table?

Because almost nobody actually wants a dead <table> blob. They want rows that correspond to real data: users, invoices, leads, inventory. Without a backend, the agent can only hard-code rows into the component, and the next request ('edit a row,' 'add a row,' 'load from an endpoint') forces a rewrite. With Postgres wired from turn one, the table has somewhere to write to, and iteration loops stay short.

Where is the Neon database actually created?

In src/core/service-provisioning.ts at the provisionNeon function around line 163. It POSTs to https://console.neon.tech/api/v2/projects with region_id 'aws-us-east-2' and pg_version 17, and the response fills in DATABASE_URL, NEON_HOST, NEON_DB_NAME, NEON_ROLE_NAME, and NEON_ROLE_PASSWORD before any agent prompt runs. The project name is mk0r-<first 12 chars of the session key>.

How does the agent know DATABASE_URL is there?

Because the VM's CLAUDE.md documents it. The file rendered at src/core/vm-claude-md.ts line 1273 includes a Neon section telling the model which env vars exist, how to install @neondatabase/serverless or drizzle-orm, and how to run CREATE TABLE statements via raw SQL. The agent reads that during session warm-up and stops asking you for credentials.

Can I still get a plain HTML + inline CSS table if that is what I want?

Yes. Ask for 'a single HTML file with inline styles, no JavaScript, no backend.' The agent drops the Postgres path and scaffolds a portable static file you can paste into a CMS, email template, or legacy page. You lose the live query and the iteration surface, but you get the raw string every traditional table generator for HTML ships.

What happens the first time I ask for 'a table of customers' with no data?

The agent treats the table generator for HTML as three jobs, not one. It CREATEs a customers table in the provisioned Neon project, INSERTs 15-25 plausible seed rows, writes a src/components/CustomersTable.tsx that queries them with neon(process.env.DATABASE_URL), and imports it into App.tsx. All of that lands as a single git commit inside the sandbox.

Does this actually work offline or does it need network?

Neon is remote Postgres, so the VM needs egress. That egress already exists: Vite runs inside an E2B sandbox that has its own network namespace, and the Neon host (NEON_HOST) is resolvable from it by default. If you prefer in-memory state for a throwaway page, ask the agent to use React useState instead of DATABASE_URL; it will comply and the Neon project will simply sit unused.

Can I export the rendered table as static HTML once I'm happy with it?

Yes. Ask the agent to 'render the table server-side with current DB rows and output plain HTML with inline styles.' It reads from Neon, serializes the resulting markup, and hands you a string you can paste anywhere. Because the shape was driven by your real schema, the cells are already in the right format.

Is there a row limit or storage cap?

Each per-session Neon project has its own free-tier storage envelope. For SEO-sized tables (hundreds to low-thousands of rows), it is effectively unlimited for this use case. If you want a production deployment, ask the agent to run npx drizzle-kit push against the same DATABASE_URL after migrating to Drizzle; the schema then lives under version control.

Do I need an account to try this?

No. Go to mk0r.com, describe the table you want, and the VM plus the Neon project plus the Vite dev server plus the git repo spin up behind an anonymous Firebase session. The default model is pinned to claude-haiku-4-5 via FREE_MODEL in src/app/api/chat/model/route.ts line 5, so there is no card, no signup, and no plan picker.

How is this different from tablesgenerator.com, divtable.com, or rapidtables.com?

Those generate a static <table> or <div> string and stop there. No schema, no storage, no query. mk0r's output on turn one is a rendered HTML table plus a live Postgres table in a dedicated Neon project plus the React component that connects the two. The string they give you is a deliverable; mk0r's output is a running feature.

The fastest way to understand this is to build one

Describe the columns. Ask for seed rows. Ask for an edit handler. Every step is a Postgres mutation plus a git commit you can walk back.

Start building on mk0r