# Import a Postgres schema The Database Visualizer is not Bubble-only. Paste in a Postgres schema from Supabase, a migration file or a `pg_dump`, and you get the same diagram. ## What is supported **Postgres only.** MySQL, SQL Server and SQLite dialects are not parsed. Upload a `.sql` file, or paste the SQL into the **Postgres / SQL** panel on the Database Visualizer. Uploads are routed by extension: `.sql` goes to the SQL parser, `.json` and `.bubble` go to the Bubble JSON parser, and any other extension is refused before the file is read. Pasted text has no filename, so it is routed by what is in it instead. [[img:import-a-postgres-schema/01-paste-panel.png|The Postgres / SQL panel, below the four upload cards. It is the only paste box on the page, and it takes Bubble JSON as happily as it takes SQL.]] ## What gets read | Construct | Becomes | |---|---| | `CREATE TABLE` | A data type | | `CREATE TYPE … AS ENUM` | An option set | | `REFERENCES` on a column | A one-to-one relationship | | `ALTER TABLE … ADD CONSTRAINT … FOREIGN KEY` | A one-to-one relationship | | `CHECK (col IN ('a','b'))` | An option set named `_` | | A `_options` table with `value` and `label` columns | An option set | | `NOT NULL`, `UNIQUE` | Kept for the round trip back out to SQL | | `type[]` | A list field | | `INSERT INTO … VALUES` | Option set values | Column types are mapped onto Bubble's vocabulary: booleans become `boolean`, timestamps and dates become `date`, all numeric types become `number`, and everything else including `uuid`, `jsonb` and `varchar` becomes `text`. `id`, `created_at` and `updated_at` columns are suppressed as fields, because Bubble creates its own equivalents. ## Three ways an option set is recognised This trips people up, so it is worth stating explicitly. A fixed set of choices in Postgres can be modelled at least three ways, and LumiDevKit understands all three: 1. A native `CREATE TYPE … AS ENUM`. 2. An inline `CHECK (status IN ('draft','published'))`. 3. A lookup table whose name ends in `_options` and which has both a `value` and a `label` column. ## The `lumidevkit:` markers Some intent cannot be recovered from SQL alone, so LumiDevKit's own SQL export writes comment markers that it reads back on import: ```sql COMMENT ON TABLE priority_options IS 'lumidevkit:option_set'; COMMENT ON TABLE tasks_watchers IS 'lumidevkit:join'; COMMENT ON TABLE profiles IS 'lumidevkit:user'; COMMENT ON COLUMN tasks.owner_id IS 'lumidevkit:display=Owner'; ``` The `join` marker is the significant one. A junction table is folded back into a list field on its owner **only when it is explicitly marked**. Unmarked two-foreign-key tables are kept as data types on purpose: a table like `votes` or `memberships` with its own surrogate id is indistinguishable from a pure join table once it has been parsed, and keeping it is the lossless choice. ## What is dropped by design Row-level security policies, triggers, functions, indexes, views, sequences, extensions, `DEFAULT` values, numeric precision, `ON DELETE` behaviour, composite primary keys and schema qualification are all discarded. The diagram models entities and relationships, not a full database. ## Import notes Where the parser makes a judgement call, it tells you underneath the drop zone: - *Treated "X" as an option set (looks like a lookup table).* - *Folded join table "X" into a list field on "Y".* - *Skipped join table "X" (needs two foreign keys).* - *Skipped join table "X" (owner "Y" not found).* Read them. They are the difference between a diagram you can trust and one you assume is right. ## If it fails You get *"Could not parse SQL: …"* with the underlying parser's message and a line number. The usual causes are a non-Postgres dialect, or a file that is a data dump rather than a schema. ## Going the other way See [export your schema](/docs/export-your-schema) for turning a Bubble schema into Postgres.