Replit includes a built-in PostgreSQL database with 10 GB of free storage that provisions automatically — no external account needed. The database auto-injects DATABASE_URL and connection credentials as environment variables, includes a Drizzle Studio visual editor, and maintains separate development and production instances. The main gotcha: the database sleeps after 5 minutes without queries, so implement reconnection logic for production apps.
Replit's Built-In PostgreSQL: Zero-Config Relational Database for Every Project
Most cloud development environments require you to create an external database account, copy a connection string, configure SSL, and manage environment variables yourself. Replit eliminates all of this. Every Replit project can enable a built-in PostgreSQL database that provisions in seconds, automatically injects six environment variables including the full DATABASE_URL, and includes a visual data editor called Drizzle Studio directly in the sidebar.
The database runs on Replit's own Helium infrastructure — a purpose-built PostgreSQL hosting layer migrated from Neon in December 2025. It provides 10 GB of storage per database on all plans, full PostgreSQL compatibility including JSON columns, indexes, foreign keys, and transactions, and time-travel rollback capabilities for recovering from accidental deletes. Because the database lives inside the Replit ecosystem, there are no IP whitelist issues, no SSL configuration hassles, and no credential management — the credentials are simply always available.
The one important limitation to understand before building: the database sleeps after approximately 5 minutes without queries. For development projects and background jobs this rarely matters, but for production web apps that might experience brief idle periods, you need reconnection logic in your database layer. This guide covers the sleep behavior, the recommended reconnection pattern, and how to think about dev/prod database separation.
Integration method
Replit's built-in PostgreSQL database is provisioned automatically for every Replit project with no setup required. It runs on Replit's own 'Helium' infrastructure (migrated from Neon in December 2025) and automatically injects DATABASE_URL, PGHOST, PGUSER, PGPASSWORD, PGDATABASE, and PGPORT as environment variables. Development and production databases are kept separate, and Drizzle Studio provides a visual table browser directly inside the editor. No external database account, no IP whitelisting, and no connection string copying needed.
Prerequisites
- A Replit account — the built-in PostgreSQL database is available on all plans
- A Replit project (Node.js, Python, or any language that supports PostgreSQL drivers)
- Basic understanding of SQL — CREATE TABLE, INSERT, SELECT statements
- No external database account needed — the database is fully managed by Replit
Step-by-step guide
Enable the built-in PostgreSQL database
Enable the built-in PostgreSQL database
Open your Replit project and look at the left sidebar. You will see a database cylinder icon labeled 'Database.' Click it to open the Database panel. If your project does not yet have a database, you will see a button labeled 'Create a database' or 'Enable PostgreSQL.' Click it. Replit provisions a PostgreSQL database in approximately 10–30 seconds. Once provisioned, the panel shows two tabs: one for the development database (used while coding in the editor) and one for the production database (used by deployed apps). You will also see a connection string and individual credential fields displayed. These credentials are automatically injected as environment variables — you do not need to copy them anywhere. The six auto-injected variables are: DATABASE_URL (full connection string), PGHOST, PGPORT, PGDATABASE, PGUSER, and PGPASSWORD. These are available immediately in all your code via os.environ in Python and process.env in Node.js, with no additional configuration needed.
Enable the built-in PostgreSQL database for my Replit project. Show me what environment variables are available and how to verify the connection is working.
Paste this in Replit chat
Pro tip: The development and production databases are completely separate instances. Data you insert while coding in the editor will NOT appear in your deployed app's database, and vice versa. This is intentional and keeps your test data from polluting production.
Expected result: The Database panel shows a green status indicator, the database is provisioned, and DATABASE_URL is listed. Running console.log(process.env.DATABASE_URL) or print(os.environ['DATABASE_URL']) in your code prints a PostgreSQL connection string.
Connect your application to the database
Connect your application to the database
With the database provisioned and credentials auto-injected, connecting your app requires only installing a database driver and writing a few lines of connection code. For Node.js apps, the most common options are the pg library (raw SQL), Prisma (type-safe ORM), or Drizzle (lightweight ORM). For Python apps, the standard choices are psycopg2 (raw SQL) or SQLAlchemy (ORM). In all cases, the connection string is the same: read DATABASE_URL from the environment. There is no need to construct a connection string manually or configure SSL separately — Replit's built-in database uses a local network connection that does not require SSL. For production resilience, use connection pooling rather than creating a new connection on every request. The pg library's Pool class and SQLAlchemy's engine both handle pooling automatically. The most important pattern for Replit's database: implement reconnect logic because the database sleeps after 5 minutes of inactivity, and a sleeping database causes the first query after idle to fail with a connection error before the database wakes up.
Connect my app to the built-in Replit PostgreSQL database. Use Drizzle ORM for Node.js (or SQLAlchemy for Python). Set up the connection using DATABASE_URL and create a basic test query to verify it works.
Paste this in Replit chat
1// Node.js — using pg with connection pooling2const { Pool } = require('pg');34const pool = new Pool({5 connectionString: process.env.DATABASE_URL,6 // No SSL needed for Replit's built-in database7 // For external PostgreSQL providers, add: ssl: { rejectUnauthorized: false }8 max: 10, // max pool size9 idleTimeoutMillis: 60000, // close idle connections after 60s10 connectionTimeoutMillis: 5000 // fail fast if can't connect in 5s11});1213// Test connection on startup14pool.query('SELECT NOW()', (err, res) => {15 if (err) {16 console.error('Database connection failed:', err.message);17 } else {18 console.log('Database connected at:', res.rows[0].now);19 }20});2122module.exports = pool;2324---2526# Python — using psycopg2 with connection pool27import os28import psycopg229from psycopg2 import pool3031connection_pool = psycopg2.pool.SimpleConnectionPool(32 minconn=1,33 maxconn=10,34 dsn=os.environ['DATABASE_URL']35)3637def get_connection():38 return connection_pool.getconn()3940def release_connection(conn):41 connection_pool.putconn(conn)4243# Test connection44conn = get_connection()45with conn.cursor() as cur:46 cur.execute('SELECT NOW()')47 print('Connected at:', cur.fetchone()[0])48release_connection(conn)Pro tip: Install packages with Replit's Universal Package Manager. For Node.js: click the Packages icon and search for 'pg' or run npm install pg in the Shell. For Python: search for 'psycopg2-binary' (not 'psycopg2' — the binary version avoids Nix dependency issues on Replit).
Expected result: Your app starts and logs 'Database connected at: [timestamp]'. The connection succeeds using only the auto-injected DATABASE_URL environment variable.
Create tables and seed initial data
Create tables and seed initial data
With the connection established, create your database schema. You can do this in three ways on Replit: using the SQL runner in the Database panel sidebar (good for quick schema setup), using the Replit Agent (good for generating and running migrations from a description), or by writing migration code in your application (good for production apps that need version-controlled schema changes). The Agent approach is the fastest for getting started: describe your data model in plain English and the Agent generates both the CREATE TABLE statements and the corresponding application code. For a more structured approach, use Drizzle's schema definition and migration system or Prisma's schema file. Both ORM tools generate type-safe client code from your schema definition, which catches column name typos and type mismatches at compile time. When seeding initial data for development, use INSERT statements or your ORM's seed script. Remember that seed data inserted in development mode stays in the development database — it will not appear in production. If you need the same initial data in production, run the seed against the production database explicitly after deploying.
Create the database schema for my app. I need a users table (id, email, password_hash, created_at) and a projects table (id, user_id as foreign key, name, description, status, updated_at). Generate the migration SQL and set up Drizzle ORM schema definitions.
Paste this in Replit chat
1// Drizzle ORM schema — schema.js2const { pgTable, serial, text, timestamp, varchar, integer } = require('drizzle-orm/pg-core');34exports.users = pgTable('users', {5 id: serial('id').primaryKey(),6 email: varchar('email', { length: 255 }).notNull().unique(),7 passwordHash: text('password_hash').notNull(),8 createdAt: timestamp('created_at').defaultNow().notNull()9});1011exports.projects = pgTable('projects', {12 id: serial('id').primaryKey(),13 userId: integer('user_id').references(() => exports.users.id).notNull(),14 name: varchar('name', { length: 255 }).notNull(),15 description: text('description').default(''),16 status: varchar('status', { length: 50 }).default('active').notNull(),17 updatedAt: timestamp('updated_at').defaultNow().notNull()18});1920// Run migration: drizzle-kit push (or use the SQL runner in Replit Database panel)Pro tip: Use the SQL runner in the Database panel (click the >_ icon inside the Database panel) for quick schema changes during development. For production apps, use a proper migration tool like Drizzle Kit or Prisma Migrate so schema changes are versioned and reproducible.
Expected result: Your tables are created and visible in Drizzle Studio. You can INSERT a test row and SELECT it back successfully.
Open Drizzle Studio to browse your data visually
Open Drizzle Studio to browse your data visually
Replit includes Drizzle Studio, a visual database browser, directly in the editor. To open it, click the Database icon in the sidebar, then click the 'Open Drizzle Studio' button in the Database panel. Drizzle Studio opens as an embedded tab showing all your tables in a spreadsheet-style interface. You can browse rows, edit values inline, add new rows, and run raw SQL queries — all without writing any code. This is the fastest way to verify that your application is inserting data correctly, inspect foreign key relationships, or quickly fix a bad row in development. Drizzle Studio connects to your development database by default. When you deploy your app and need to inspect production data, you can connect Drizzle Studio to the production database by switching the database connection in the panel (click the database name dropdown in the sidebar). Be careful when editing production data directly — there is no undo for manual edits made outside your application code.
Open Drizzle Studio and show me my users table. I want to add a test user row manually to verify my connection is working.
Paste this in Replit chat
Pro tip: Drizzle Studio is for the built-in Replit database only. If you are using an external PostgreSQL provider like Supabase or Neon, use their own dashboard tools to browse data.
Expected result: Drizzle Studio opens in a browser tab and displays your table list on the left and rows on the right. You can see any rows you have inserted and edit them inline.
Handle the 5-minute sleep behavior in production
Handle the 5-minute sleep behavior in production
Replit's built-in PostgreSQL database sleeps after approximately 5 minutes without any queries. This is a cost-saving measure that works well for development but requires special handling for production web apps. When the database is asleep and your app tries to connect, the first query will fail with a connection error (typically 'Connection refused' or 'ECONNREFUSED'), and the database will start waking up. Subsequent queries — usually within 1–3 seconds — will succeed. The solution is to implement retry logic in your database layer so that a single failed query triggers a brief wait and retry rather than returning an error to your user. In practice, for apps deployed on Autoscale Deployment (which itself scales to zero), both the app and the database may be asleep simultaneously when a user first visits. The combined cold start can take 3–5 seconds. For apps where this latency is unacceptable, use a Reserved VM Deployment (which keeps your app always running) and ensure your database connection pool sends a keepalive query (e.g., SELECT 1) every few minutes to prevent the database from sleeping. The pg library's keepAlive option and connection heartbeat interval settings handle this automatically.
My database connection fails occasionally with a connection refused error after the app has been idle. Add retry logic and connection keepalive to prevent the database from sleeping and causing errors for users.
Paste this in Replit chat
1// Node.js — pg Pool with keepalive and retry wrapper2const { Pool } = require('pg');34const pool = new Pool({5 connectionString: process.env.DATABASE_URL,6 max: 10,7 idleTimeoutMillis: 60000,8 connectionTimeoutMillis: 5000,9 // Send keepalive to prevent database sleep during idle periods10 keepAlive: true,11 keepAliveInitialDelayMillis: 200000 // start keepalive after ~3 min idle12});1314// Retry wrapper for transient connection failures15async function queryWithRetry(text, params, retries = 3) {16 for (let i = 0; i < retries; i++) {17 try {18 return await pool.query(text, params);19 } catch (err) {20 if (i === retries - 1) throw err;21 if (err.code === 'ECONNREFUSED' || err.message.includes('Connection')) {22 console.log(`DB connection attempt ${i + 1} failed, retrying in 2s...`);23 await new Promise(r => setTimeout(r, 2000));24 } else {25 throw err; // Non-connection errors should not be retried26 }27 }28 }29}3031module.exports = { pool, queryWithRetry };Pro tip: For production apps on Reserved VM Deployment, you can send a keepalive query on a schedule to prevent the database from sleeping. Add setInterval(() => pool.query('SELECT 1'), 240000) (every 4 minutes) to your server startup code.
Expected result: Connections that previously failed with 'ECONNREFUSED' now automatically retry and succeed. The console shows 'DB connection attempt 1 failed, retrying in 2s...' followed by a successful query on the second attempt.
Common use cases
Full-Stack Web App with User Data
A Replit app that handles user authentication, profiles, and app-specific records needs a relational database. The built-in PostgreSQL database stores users, sessions, and application data with proper foreign keys and indexes — ready to use without any external account setup.
Set up the database for my app. Create a users table with id, email, name, created_at, and a subscription_status column. Create a posts table linked to users. Use Drizzle ORM and connect to the built-in Replit PostgreSQL database using the DATABASE_URL environment variable.
Copy this prompt to try it in Replit
API Backend with Persistent Storage
A REST API built on Replit needs to persist data between requests. The built-in PostgreSQL database handles concurrent connections from API routes, supports complex queries with JOINs and aggregations, and keeps data consistent across Autoscale deployment restarts.
Add a PostgreSQL database to my Express API. I need to store product inventory with fields: id, name, price, quantity, category. Set up the connection using the DATABASE_URL environment variable and implement CRUD routes for the products table.
Copy this prompt to try it in Replit
Data Processing and Analytics Backend
A Python data pipeline running on Replit processes incoming data and stores results in PostgreSQL for later querying. The Agent connects to the built-in database using psycopg2 or SQLAlchemy, creates the schema, and writes processed records in batches.
I need to process CSV data and store results in PostgreSQL. Set up a Python script that reads a CSV file, cleans the data, and inserts rows into a results table using psycopg2. Connect to the built-in Replit database using DATABASE_URL from environment variables.
Copy this prompt to try it in Replit
Troubleshooting
Error: connect ECONNREFUSED or 'Connection refused' when querying the database
Cause: The built-in PostgreSQL database has entered its sleep state after 5 minutes without queries. The first connection attempt after sleep fails while the database wakes up.
Solution: Implement retry logic in your database query wrapper (see Step 5). For production apps on Reserved VM, add a keepalive interval that queries SELECT 1 every 4 minutes to prevent sleep from occurring.
1// Simple retry for one-off scripts2async function queryWithRetry(pool, sql, params) {3 try {4 return await pool.query(sql, params);5 } catch (err) {6 if (err.code === 'ECONNREFUSED') {7 await new Promise(r => setTimeout(r, 3000));8 return pool.query(sql, params); // one retry9 }10 throw err;11 }12}DATABASE_URL is undefined when accessing process.env.DATABASE_URL or os.environ['DATABASE_URL']
Cause: The PostgreSQL database has not been enabled for this project yet, or the project was created before the database was enabled and the environment variables have not been injected into the current session.
Solution: Open the Database panel in the Replit sidebar and click 'Enable PostgreSQL' or 'Create a database' if it has not been set up. If the database is already provisioned but the variable is missing, stop and restart the Repl (click Stop then Run) to refresh the environment variable injection.
Data inserted in development does not appear when the app is deployed
Cause: Replit maintains separate development and production database instances. Data written in the editor environment goes to the development database; the deployed app uses the production database, which starts empty.
Solution: If you need the same seed data in production, either run your seed script against the production database after deploying, or use a migration tool that runs schema and seed scripts automatically on startup. You can also use the Database panel to switch to the production database view and manually insert rows via Drizzle Studio.
Best practices
- Always use connection pooling (Pool in pg, engine with pool settings in SQLAlchemy) rather than creating individual connections per request
- Implement reconnection retry logic to handle the database sleep behavior gracefully — never surface 'ECONNREFUSED' errors directly to users
- Use an ORM like Drizzle or Prisma to get type-safe database access and a structured migration workflow instead of writing raw SQL strings
- Keep development and production databases as separate as possible — do not share data between them to avoid data contamination
- Run a keepalive SELECT 1 query every 4 minutes on Reserved VM deployments to prevent the database from entering sleep state during low-traffic periods
- Use the SQL runner in Drizzle Studio for quick schema exploration, but rely on migration files (Drizzle Kit push, Prisma Migrate) for any changes you need to reproduce in production
- Store sensitive computed data (passwords, tokens) as hashed values using bcrypt or similar — never store plaintext credentials in the database
- Set up a scheduled Replit job or application-level startup task to run pending migrations automatically when your app deploys, so schema and app are always in sync
Alternatives
MongoDB Atlas is a hosted NoSQL document database that works with Replit but requires an external account, an open IP whitelist (0.0.0.0/0) due to Replit's dynamic IPs, and manual connection string setup — unlike PostgreSQL's zero-config built-in experience.
MySQL requires an external hosting provider (PlanetScale, AWS RDS) since there is no built-in Replit MySQL database, adding setup complexity compared to the auto-provisioned PostgreSQL option.
Airtable provides a spreadsheet-style database with a visual UI that's accessible without SQL knowledge, making it better for non-technical users managing data, while PostgreSQL is the better choice for programmatic access and complex queries.
Frequently asked questions
How much storage does the built-in Replit PostgreSQL database include?
The built-in PostgreSQL database provides 10 GB of storage per database on all Replit plans. Each project has a separate development database and a separate production database, each with its own 10 GB limit. This is enough for most production web apps and APIs; large media files should be stored in an object storage service like AWS S3 rather than the database.
Does the Replit PostgreSQL database have a sleep timeout?
Yes. The database sleeps after approximately 5 minutes without any queries. The first connection attempt after sleep may fail while the database wakes up (typically 1–3 seconds). For production apps, implement retry logic in your database layer and use a keepalive query interval on Reserved VM deployments to prevent sleep from occurring during low-traffic periods.
Can I use Prisma, Drizzle, or SQLAlchemy with the built-in database?
Yes, all standard PostgreSQL ORMs and query builders work with Replit's built-in database. The connection string is available in DATABASE_URL and follows the standard postgresql:// format. For Prisma, set DATABASE_URL in your schema.prisma datasource block. For Drizzle, pass DATABASE_URL to drizzle-orm/node-postgres. For SQLAlchemy, use create_engine(os.environ['DATABASE_URL']).
Are the development and production databases the same?
No. Replit maintains completely separate development and production database instances. The development database is used when you run code in the editor; the production database is used by your deployed app. This prevents test data from appearing in production. To share schema between them, use database migrations that run in both environments.
How do I view and edit my database data visually?
Replit includes Drizzle Studio, accessible by clicking the Database icon in the sidebar and then clicking 'Open Drizzle Studio.' It provides a spreadsheet-style interface to browse rows, edit values, add rows, and run raw SQL queries against your development or production database. For external PostgreSQL databases, use your provider's own dashboard tool.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation