Skip to main content
Dreamlit integrates with any PostgreSQL-compatible database (including Supabase, Neon, RDS, Cloud SQL, Render, Railway, self-hosted, etc.), letting you trigger notification workflows from database events.

How Dreamlit interacts with your database

On a high level, Dreamlit needs to know where your data lives in your database, install database triggers (for database trigger workflows), and manage some housekeeping tables in a separate schema. This way:
  • Dreamlit’s AI can propose the relevant workflows for you by introspecting your database structure to understand the shape of your data and where it lives.
  • You can preview your workflows with live database rows.
  • You can react to new events happening in your app in real-time.
Dreamlit never edits, deletes, inserts, or otherwise modifies data in your database. For a full technical deep dive, check out the how it works page.

Permissions needed

The Postgres user/role you provide to Dreamlit must at least have the following permissions:
  • Read relevant tables (SELECT) so Dreamlit’s AI can setup workflows for you and you can preview workflows with live database rows.
  • Create triggers on tables to launch workflows right away when events occur.
  • Manage its own dreamlit schema for housekeeping and logging.
Dreamlit does not need edit, delete, or insert permissions on your tables as it never mutates or modifies your data. Of course, if you already have a user with the sufficient privileges (such as a superuser) you can use that. However, it is best practice to create a separate Postgres user for each service that needs access to your database, following the principles of isolation and least privilege. Instructions to do this are below.

Commands to run to setup your dreamlit_app database user

It’s recommended to create a separate Postgres database user for each service that needs access to your database.This way, you can grant only the necessary permissions for each service and you can selectively revoke access as needed.
Dreamlit needs the permissions as outlined in the previous section. Follow the instructions below to setup the dreamlit_app user and grant the necessary permissions.
  1. Generate a strong, unique password on your own (e.g., with a password generator).
  2. Fill in the details for your database connection in the applet below. For the host, be sure to use a transaction pooler like PgBouncer if available to avoid exhausting connection limits.
  3. Hit Generate.
  4. Copy the SQL commands and run them in your database as a superuser (e.g., postgres or neondb_owner), substituting [[REPLACE_WITH_PASSWORD]] with your password from step 1 with single quotes like 'mypassword'. This creates the dreamlit_app user and grants the minimal necessary permissions.
  5. Copy the connection string (after replacing the password placeholder, this time without single quotes) into Dreamlit to connect your database and finish setup.
If you’re using RLS (row level security), be sure to turn on the Add RLS policies option in Advanced configuration in the applet above so that the dreamlit_app can SELECT rows on RLS-enabled tables.For any tables you create in the future, you will need to ensure there is an appropriate RLS policy created for the dreamlit_app to SELECT rows, by either adding policies manually or rerunning the generator above (the commands generated are idempotent, so you can re-run mulitple times as needed).
Run these SQL commands in your database as a superuser (e.g., postgres), or ideally as the same role that creates schemas/tables in your app so default privileges attach to future schemas:

1. Create a dedicated Dreamlit user

First, we create a new database user specifically for Dreamlit with a secure password. Be sure to replace <SECRET_PASSWORD> below with a strong, unique password.
CREATE USER dreamlit_app WITH PASSWORD '<SECRET_PASSWORD>' INHERIT;

2. Grant database-level privileges

Grant the Dreamlit user basic database access. Be sure to replace <YOUR_DATABASE_NAME> below with the name of your database (e.g., defaultdb or postgres).
GRANT CONNECT ON DATABASE <YOUR_DATABASE_NAME> TO dreamlit_app;
GRANT CREATE ON DATABASE <YOUR_DATABASE_NAME> TO dreamlit_app;
GRANT TEMP ON DATABASE <YOUR_DATABASE_NAME> TO dreamlit_app;

3. Install pgcrypto (required)

gen_random_uuid() is used by Dreamlit’s housekeeping objects. Install the extension in the target database:
CREATE EXTENSION IF NOT EXISTS pgcrypto;

4. Grant view + trigger permissions on your application tables

Grant the Dreamlit user access to your schemas and set default privileges so future tables work too. Replace <YOUR_SCHEMA_NAME> with each schema (e.g., public) and <TABLE_CREATOR_ROLE> with the role that creates future tables (your migrations/app owner). Two knobs:
  • Scope: run the GRANT block for each schema you want to expose. If you prefer “all schemas”, run the backfill block below once.
  • Future objects: global default privileges (shown here) apply to all future schemas/objects created by <TABLE_CREATOR_ROLE>. If you prefer schema-scoped defaults, swap the global lines for ... IN SCHEMA <YOUR_SCHEMA_NAME> ....
GRANT USAGE ON SCHEMA <YOUR_SCHEMA_NAME> TO dreamlit_app;
GRANT SELECT, TRIGGER ON ALL TABLES IN SCHEMA <YOUR_SCHEMA_NAME> TO dreamlit_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA <YOUR_SCHEMA_NAME> TO dreamlit_app;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA <YOUR_SCHEMA_NAME> TO dreamlit_app;

-- Global defaults so future schemas/objects created by this role are accessible
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE>
  GRANT USAGE ON SCHEMAS TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE>
  GRANT SELECT, TRIGGER ON TABLES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE>
  GRANT USAGE, SELECT ON SEQUENCES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE>
  GRANT EXECUTE ON FUNCTIONS TO dreamlit_app;
Optional: Sync existing schemas Run this once as the table owner (e.g., postgres) to backfill grants across all existing schemas (grants on current objects; use this if you chose “all schemas” or want to catch up existing ones). Global defaults above already cover future objects; remove the global lines if you prefer per-schema defaults and swap in IN SCHEMA ... per your needs.
DO $$
DECLARE
  target_role text := 'dreamlit_app';
  parent_role text := '<TABLE_CREATOR_ROLE>';
  schema_record record;
BEGIN
  FOR schema_record IN
    SELECT nspname
    FROM pg_namespace
    WHERE nspname NOT IN ('pg_catalog', 'information_schema', 'auth')
      AND nspname NOT LIKE 'pg_toast%'
  LOOP
    IF parent_role IS NULL OR has_schema_privilege(parent_role, schema_record.nspname, 'USAGE') THEN
      EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', schema_record.nspname, target_role);
      EXECUTE format('GRANT SELECT, TRIGGER ON ALL TABLES IN SCHEMA %I TO %I', schema_record.nspname, target_role);
      EXECUTE format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA %I TO %I', schema_record.nspname, target_role);
      EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA %I TO %I', schema_record.nspname, target_role);
    END IF;
  END LOOP;
END;
$$;
Run this query to see which role owns your existing tables:
SELECT tableowner, COUNT(*) as table_count
FROM pg_tables
WHERE schemaname = '<YOUR_SCHEMA_NAME>'
GROUP BY tableowner;
Use the role name from the tableowner column in the ALTER DEFAULT PRIVILEGES commands above.
If any of your tables have RLS enabled (common for Supabase projects if you use the “anon” role), you must create policies that allow the newly created dreamlit_app to SELECT rows. Otherwise, you won’t be able to read the data needed for your Dreamlit workflows.If you’re not sure, you can run the following command to check which tables have RLS enabled:
-- First, check which tables have RLS enabled
SELECT schemaname, tablename, rowsecurity
FROM pg_tables
WHERE schemaname = '<YOUR_SCHEMA_NAME>' AND rowsecurity = true;
If the above query returns any rows, then you have RLS enabled and you’ll need to create a policy for each table that allows the dreamlit_app to SELECT rows.Run the following command to generate the policy creation commands for all RLS-enabled tables:
-- Generate CREATE POLICY commands for all RLS-enabled tables
SELECT 'CREATE POLICY dreamlit_app_select_policy ON ' || schemaname || '.' || tablename ||
      ' FOR SELECT TO dreamlit_app USING (true);' as policy_command
FROM pg_tables
WHERE schemaname = '<YOUR_SCHEMA_NAME>' AND rowsecurity = true;
Finally, copy and execute the commands returned from the above query.For future tables: Unfortunately, PostgreSQL doesn’t support default RLS policies like it does for privileges. You’ll need to remember to create a policy whenever you add a new table with RLS enabled.

5. Construct your new connection string

Construct your PostgreSQL connection string using the dreamlit_app and the <SECRET_PASSWORD> you created. Provide this string to Dreamlit.
Use the Pooler connection details from your Supabase dashboard. You must add your Project Ref to the username.
postgresql://dreamlit_app.<YOUR_PROJECT_REF>:<SECRET_PASSWORD>@<SUPABASE_POOLER_HOST>:<POOLER_PORT>/postgres
  • Replace <YOUR_PROJECT_REF>, <SUPABASE_POOLER_HOST>, and <POOLER_PORT> (usually 6543) with values from your Supabase Database settings.
Use the Pooled connection details from your Neon dashboard. The username is just dreamlit_app.
postgresql://dreamlit_app:<SECRET_PASSWORD>@<NEON_POOLED_HOST>:<NEON_PORT>/<NEON_DB_NAME>
  • Replace <NEON_POOLED_HOST>, <NEON_PORT>, and <NEON_DB_NAME> with values from your Neon Connection Details.
Use your standard database connection details.
postgresql://dreamlit_app:<SECRET_PASSWORD>@<YOUR_DATABASE_HOST>:<PORT>/<YOUR_DATABASE_NAME>
  • Replace <YOUR_DATABASE_HOST>, <PORT> (usually 5432), and <YOUR_DATABASE_NAME> with your database’s connection details.
Connect to your pooler’s address. The database name might be an alias defined in the pooler config.
postgresql://dreamlit_app:<SECRET_PASSWORD>@<YOUR_POOLER_HOST>:<POOLER_PORT>/<DB_NAME_ALIAS_IN_POOLER>
  • Replace <YOUR_POOLER_HOST>, <POOLER_PORT> (e.g., 6432), and <DB_NAME_ALIAS_IN_POOLER> with your pooler’s specific details. Check pooler configuration if unsure.
Copy the correctly formatted connection string and paste it into the Dreamlit connection setup field.

Troubleshooting

If you see an error like permission denied for table X or must be owner of relation X when Dreamlit tries to create triggers, it means the Dreamlit user lacks TRIGGER permission (or ownership) on that table.Quick checks:
  • Confirm Postgres version is 14+ (TRIGGER privilege is grantable starting in 14).
  • Verify the grant actually landed: SELECT has_table_privilege('dreamlit_app','<SCHEMA>.<TABLE>','TRIGGER');
Solution (pick one):
-- Grant trigger rights on the table
GRANT TRIGGER ON TABLE <SCHEMA>.<TABLE> TO dreamlit_app;

-- For future tables in the schema (run as the table owner, often postgres or your app role)
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE> IN SCHEMA <SCHEMA>
  GRANT TRIGGER ON TABLES TO dreamlit_app;

-- Or transfer ownership to a dedicated owner role you control:
ALTER TABLE <SCHEMA>.<TABLE> OWNER TO <APP_OWNER_ROLE>;
GRANT <APP_OWNER_ROLE> TO dreamlit_app;
If you see permission denied for schema dreamlit, the schema privileges were not applied correctly.Fix (run as the schema owner or a superuser):
  1. Find who owns the schema:
SELECT schema_owner
FROM information_schema.schemata
WHERE schema_name = 'dreamlit';
  1. Easiest path: make dreamlit_app the owner so it can self-manage:
ALTER SCHEMA dreamlit OWNER TO dreamlit_app;
  1. If you must keep the current owner, grant explicit rights to dreamlit_app:
GRANT USAGE, CREATE ON SCHEMA dreamlit TO dreamlit_app;
GRANT ALL ON ALL TABLES IN SCHEMA dreamlit TO dreamlit_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA dreamlit TO dreamlit_app;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA dreamlit TO dreamlit_app;
  1. Keep future objects accessible (replace <SCHEMA_OWNER> with the owner from step 1):
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT ALL ON TABLES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT USAGE, SELECT ON SEQUENCES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT EXECUTE ON FUNCTIONS TO dreamlit_app;
This appears when Dreamlit tries to create its internal table but a prior install left dreamlit.event_log owned by another role (or with different grants).Fix (pick one, run as schema owner/superuser):
  1. Reuse the existing table by granting Dreamlit access:
GRANT INSERT, SELECT, DELETE ON TABLE dreamlit.event_log TO dreamlit_app;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA dreamlit TO dreamlit_app;
  1. If you prefer Dreamlit to own the table (and the data inside is only Dreamlit logs), transfer ownership:
ALTER TABLE dreamlit.event_log OWNER TO dreamlit_app;
  1. If it’s safe to rebuild the log (non-production or you don’t need the old rows), drop and let Dreamlit recreate:
DROP TABLE dreamlit.event_log;
After any option, rerun Test Connection. If you keep a non-Dreamlit owner, also set default privileges so new Dreamlit objects stay accessible:
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT ALL ON TABLES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT USAGE, SELECT ON SEQUENCES TO dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <SCHEMA_OWNER> IN SCHEMA dreamlit
  GRANT EXECUTE ON FUNCTIONS TO dreamlit_app;
If Dreamlit reports zero rows in all tables, it might be because you have RLS enabled and you haven’t added a SELECT policy for dreamlit_app.Fix: add a SELECT RLS policy for dreamlit_app.
  • Rerun the generator above with Add RLS policies enabled in Advanced configuration (or add SELECT policies manually) so dreamlit_app can read data.
  • For new RLS tables you create later, add a SELECT policy for dreamlit_app or rerun the generator.

Uninstalling Dreamlit

If you ever want to remove Dreamlit entirely:
  1. Unpublish all workflows that depend on your Supabase connection (this removes triggers/functions).
  2. Delete the connection in the Dreamlit dashboard.
  3. (Optional) Drop the dreamlit schema and the dreamlit_app database user to remove all Dreamlit-managed objects.
If you’d like to drop the dreamlit_app role, you can issue the following commands. Replace <YOUR_DATABASE_NAME>, <YOUR_SCHEMA_NAME>, and <TABLE_CREATOR_ROLE> as appropriate. For credential rotation only, skip the optional DROP steps and just update the role password instead.
-- Revoke privileges on your schema (e.g., public)
-- Replace <TABLE_CREATOR_ROLE> with the same role used when granting default privileges
REVOKE SELECT, TRIGGER ON ALL TABLES IN SCHEMA <YOUR_SCHEMA_NAME> FROM dreamlit_app;
REVOKE USAGE, SELECT ON ALL SEQUENCES IN SCHEMA <YOUR_SCHEMA_NAME> FROM dreamlit_app;
REVOKE USAGE ON SCHEMA <YOUR_SCHEMA_NAME> FROM dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE> IN SCHEMA <YOUR_SCHEMA_NAME>
  REVOKE SELECT, TRIGGER ON TABLES FROM dreamlit_app;
ALTER DEFAULT PRIVILEGES FOR ROLE <TABLE_CREATOR_ROLE> IN SCHEMA <YOUR_SCHEMA_NAME>
  REVOKE USAGE, SELECT ON SEQUENCES FROM dreamlit_app;

-- Optional: uninstall Dreamlit objects (this drops Dreamlit logs)
REASSIGN OWNED BY dreamlit_app TO <TABLE_CREATOR_ROLE>;
DROP SCHEMA IF EXISTS dreamlit CASCADE;

-- Clean up any remaining objects owned by the role (outside your schema)
DROP OWNED BY dreamlit_app;

-- Revoke database privileges
REVOKE CONNECT, CREATE, TEMP ON DATABASE <YOUR_DATABASE_NAME> FROM dreamlit_app;

-- Finally, drop the user
DROP USER dreamlit_app;
That’s it! By connecting Postgres to Dreamlit, you can create powerful, real-time workflows triggered by database changes — without writing any custom code in your application.