# 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.